Submitting a List<T> of Items - asp.net-mvc-3

Just a quick question from a newbie to the pro's.
I am trying to implement a editable grid type form in my application. Here is the example.
#for (int i = 0; i < Model.Items.Count; i++)
{
<tr>
<td>#Html.CheckBoxFor(m => m.Items[i].fav_ind)
</td>
<td>
<a href="#" onclick="ShowDeals(#Model.Items[i].item_no);event.returnValue = false; return false;">
DEALS</a>
</td>
<td>#Html.DisplayFor(m => m.Items[i].item_no)
</td>
<td>#Html.DisplayFor(m => m.Items[i].item_desc)
</td>
<td>#Html.DisplayFor(m => m.Items[i].mfr_item)
</td>
<td>#Html.DisplayFor(m => m.Items[i].pack_size)
</td>
<td>#Html.DisplayFor(m => m.Items[i].purc_uom)
</td>
<td>#Html.DisplayFor(m => m.Items[i].purc_uom_conv)
</td>
<td>#Html.DisplayFor(m => m.Items[i].list_prc)
</td>
<td>
#Html.TextBoxFor(m => m.Items[i].nett_prc)
</td>
<td>
#Html.TextBoxFor(m => m.Items[i].Qty)
</td>
</tr>
}
This #for is inside a Html.BeginForm, because I want the user to be able to edit the last 2 fields (nett_prc and qty. There is also a submit bottom on the bottom of this grid(table).
Now for the question, when I submit, I get all the rows back in the controller, but on the items only the 2 fields where is is Html.TextBoxFor() has data in it. I want to get all the fields in the controller. I kwno I can use #Html.HiddenFor(), but I want to be able to display the other fields in labels, and when the user submits I want the values ass well.
Thanks in advance.

You can do both DisplayFor and HiddenFor at the same time:
<td>
#Html.DisplayFor(m => m.Items[i].item_no)
#Html.HiddenFor(m => m.Items[i].item_no)
</td>
However, why would you need HiddenFor? If the user is not supposed to edit some of the values, you can't trust the values that come from the form anyway. And if you can't trust them you will have to read the originals (e.g. from a database). What does HiddenFor buy you here?

Related

IEnumerable Model from view to Controller is NULL [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 4 years ago.
I am trying to return table values of my view back to the controller to save on db but I keep getting null. I can post the values without problem and bind them to the view.
I cannot understand why, I am using a server side view model.
Is there any way to perform this?
View:
#model IEnumerable<MultiEdit.Models.TableViewModel>
#using (Ajax.BeginForm("Save", "UUTs", new AjaxOptions
{
HttpMethod = "Post",
}, new { id = "tableForm" }))
{
#Html.AntiForgeryToken()
<div class="row" style="padding-top:10px;">
<div class="col-lg-12">
<table class="table table-bordered table-striped ">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.IsChassis)
</th>
<th>
#Html.DisplayNameFor(model => model.Justification)
</th>
</tr>
</thead>
<tbody id="tblMultiEdit">
#foreach(var item in Model)
{
<tr>
<td>
#Html.CheckBoxFor(modelItem => item.CheckIsChassis)
</td>
<td>
#Html.EditorFor(modelItem => item.Justification)
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
Controller:
public void Save(IEnumerable<TableViewModel> vm)
{
DoSomething();
}
You need to iterate through your collection with a for loop and index qualifier. Something like the below. The syntax is not exact but you should be able to see what I mean.
#for(var index = 0; index <= Model.Count - 1; index++)
{
<tr>
<td>
#Html.CheckBoxFor(modelItem => Model[index].CheckIsChassis)
</td>
<td>
#Html.EditorFor(modelItem => Model[index].Justification)
</td>
</tr>
}
This is required so the index can be used to create the unique id's of the Enumerable items and aids model binding
Hope that helps
I resolved it by using IList insead of IEnumerable.
View:
#model IList<MultiEdit.Models.TableViewModel>
#Html.CheckBoxFor(modelItem => modelItem[index].CheckIsChassis, new { #class = "form-control" })
Controller:
public void Save(IList<TableViewModel> vm)
{
var x = vm;
}

Kendo MultiSelect does not populate bound values

I have a MultiSelect belongs to Kendo ListView EditorTemplates. When I want to submit selected MultiSelect values, I got list of items selected, but all populated with 0 value. I cant get correct value of selected items.
Here is my ListView:
#(Html.Kendo().ListView<esCMS.Modules.C2C.Domain.c2cFieldRangeList>()
.Name("listView")
.TagName("div")
.ClientTemplateId("template")
.DataSource(dataSource => dataSource
.Model(model => model.Id(x => x.FieldRangeID))
.PageSize(6)
.Create(create => create.Action("AddRange", "Field"))
.Update(update => update.Action("UpdateRange", "Field"))
.Read(read => read.Action("ReadRange", "Field", new { id = Model.FieldID }))
))
And here is my EditorTemplates:
<table>
<tr>
<td>
#Html.LabelFor(x => x.RangeValue)
</td>
<td>
:
</td>
<td>
#Html.TextBoxFor(x => x.RangeValue, new { #class = "k-textbox", style = "width:180px" })
<span data-for="RangeValue" class="k-invalid-msg"></span>
</td>
</tr>
<tr>
<td>
#Html.LabelFor(x => x.SelectedValues)
</td>
<td>
:
</td>
<td>
#(Html.Kendo().MultiSelectFor(x=> x.SelectedValues)
.HtmlAttributes(new { style = "width:180px" })
.BindTo(new SelectList(ViewBag.Fields, "FieldID", "Title")))
</td>
</tr></table>
Edit: ViewBag.Fields contains List of c2cFieldList model and I expect to get List of FieldID when I submit view.
ViewBag.Fields = Entities.c2cField.Where(x => !x.IsGeneral && !x.IsTemp).Select(x => new c2cFieldList { Title = x.Title, FieldID = x.FieldID});
Any advice will be helpful.

MVC3 Razor and the browser (IE9) back button issue

I am developing a MVC 3 Razor app and I'm having issues when I click the back button in the browser. My application workflow:
Select a facility from a dropdown list
A WebGrid gets populated with a list of the facility's buildings.
Click an image to edit a building
Click the browser's back button and the dropdown list in step 1 appears without the CSS formatting. If I click F5 to refresh then everything resets and the CSS formatting is back.
I'm using VS2010 and the ASP.NET development server with IE9 as the default browser. I have added the OutputCache attribute to every ActionResult in the controller.
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
Here's my link in the WebGrid built from a PartialView
grid.Column(header: "",
format: #<text><a href="#Url.Action("Edit", "BuildingModels", new { #id = item.FACInventoriesId })"><img src="#Url.Content("~/Content/images/edit.png")"
alt='Edit' title='Edit' border='0'/></a></text>)
How do I get a browser to show the WebGrid (step 2) when the back button is click from editing a building (step 4)? Also any ideas why the CSS formatting is missing when I click the back button?
Here's the Controller code:
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public ViewResult Index()
{
ViewBag.Systems = buildingsVM.GetSystemsList();
return View();
}
[HttpPost]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public ActionResult GetFacilityDetails(int systemId, string facilityId)
{
try
{
ViewBag.Systems = buildingsVM.GetSystemsList();
var facility = buildingsVM.GetFacilityDetails(systemId, facilityId);
facility.Buildings = buildingsVM.GetFacilityBuildings(systemId, facilityId);
var bldgsHtml = ViewsUtility.RenderPartialViewToString(this, "_Buildings", facility.Buildings);
TempData["CurrentFacility"] = facility;
return Json(new { ok = true, facdata = facility, bldgs = bldgsHtml, message = "ok" });
}
catch (Exception ex)
{
return Json(new { ok = false, message = ex.Message });
}
}
[HttpPost]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public ActionResult GetSystemFacilities(int systemId)
{
try
{
var facilities = buildingsVM.GetFacilitesBySystemId(systemId);
return Json(new { ok = true, data = facilities, message = "ok" });
}
catch (Exception ex)
{
return Json(new { ok = false, message = ex.Message });
}
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public ActionResult Edit(int id)
{
var facility = TempData["CurrentFacility"] as FacilityModel;
return View(buildingsVM.GetBuilding(id));
}
Code from Partial View:
#model IEnumerable<COPSPlanningWeb.Models.BuildingModel>
<!-- Current Buildings from partial view -->
#{
if (Model != null && Model.Count() > 0)
{
var grid = new WebGrid(rowsPerPage: 50, defaultSort: "BuildingNumber"); //ajaxUpdateContainerId: "tabs-2",
grid.Bind(Model, rowCount: Model.Count(), autoSortAndPage: false);
grid.Pager(WebGridPagerModes.All);
#grid.GetHtml(
tableStyle: "webgridDisplay",
alternatingRowStyle: "alt",
columns: grid.Columns(
//grid.Column(format: (item) => Html.ActionLink("Edit", "Edit", new { EmployeeID = item.EmployeeID, ContactID = item.ContactID })),
grid.Column("BuildingNumber", header: "Building Number", style: "webgridDisplayCenter"),
grid.Column("ConstructionDate", header: "Construction Date", format: #<text>#item.ConstructionDate.ToString("MM/dd/yyyy")</text>),
grid.Column("ExtSquareFeet", header: "Exterior Sq. Ft.", format: (item) => string.Format("{0:n0}", item.ExtSquareFeet)),
grid.Column("IntSquareFeet", header: "Interior Sq. Ft.", format: (item) => string.Format("{0:n0}", item.IntSquareFeet)),
grid.Column("IU_Avail", header: "IU Available"),
grid.Column("SpaceAvail", header: "Space Available"),
grid.Column("FixedAssetValue", header: "Fixed Asset Value", format: (item) => string.Format("{0:C}", item.FixedAssetValue)),
grid.Column("FixedEquipValue", header: "Fixed Equipment Value", format: (item) => string.Format("{0:C}", item.FixedEquipValue)),
grid.Column(header: "",
format: #<text><a href="#Url.Action("Edit", "BuildingModels", new { #id = item.FACInventoriesId })"><img src="#Url.Content("~/Content/images/edit.png")"
alt='Edit' title='Edit' border='0'/></a></text>),
grid.Column(header: "",
format: #<text><a href="#Url.Action("Delete", "BuildingModels", new { #id = item.FACInventoriesId })"><img src="#Url.Content("~/Content/images/trash.png")"
alt='Delete' title='Delete' border='0'/></a></text>)
))
}
}
Code from Edit view:
#model COPSPlanningWeb.Models.BuildingModel
#{
ViewBag.Title = "Add/Edit Inventory";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<table style="width: 100%;" class="display">
#Html.HiddenFor(model => model.FacilityId)
#Html.HiddenFor(model => model.FACInventoriesId)
<tr>
<th colspan="2" style="text-align: left;">
Building Information - Edit Inventory
</th>
</tr>
<tr>
<td class="fieldlabel">
Facility Name
</td>
<td class="fielddata">
</td>
</tr>
<tr>
<td class="fieldlabel">
Building Number
</td>
<td class="fielddata">
#Html.EditorFor(model => model.BuildingNumber)
#Html.ValidationMessageFor(model => model.BuildingNumber)
</td>
</tr>
<tr>
<td class="fieldlabel">
Construction Date
</td>
<td class="fielddata">
#Html.EditorFor(model => model.ConstructionDate, "DateTime")
#Html.ValidationMessageFor(model => model.ConstructionDate)
</td>
</tr>
<tr>
<td class="fieldlabel">
Exterior Sq. Ft.
</td>
<td class="fielddata">
#Html.EditorFor(model => model.ExtSquareFeet)
#Html.ValidationMessageFor(model => model.ExtSquareFeet)
</td>
</tr>
<tr>
<td class="fieldlabel">
Interior Sq. Ft.
</td>
<td class="fielddata">
#Html.EditorFor(model => model.IntSquareFeet)
#Html.ValidationMessageFor(model => model.IntSquareFeet)
</td>
</tr>
<tr>
<td class="fieldlabel">
IU Available
</td>
<td class="fielddata">
#Html.EditorFor(model => model.IU_Avail)
#Html.ValidationMessageFor(model => model.IU_Avail)
</td>
</tr>
<tr>
<td class="fieldlabel">
Space Available
</td>
<td class="fielddata">
#Html.EditorFor(model => model.SpaceAvail)
#Html.ValidationMessageFor(model => model.SpaceAvail)
</td>
</tr>
<tr>
<td class="fieldlabel">
Fixed Asset Value
</td>
<td class="fielddata">
#Html.EditorFor(model => model.FixedAssetValue)
#Html.ValidationMessageFor(model => model.FixedAssetValue)
</td>
</tr>
<tr>
<td class="fieldlabel">
Fixed Equipment Value
</td>
<td class="fielddata">
#Html.EditorFor(model => model.FixedEquipValue)
#Html.ValidationMessageFor(model => model.FixedEquipValue)
</td>
</tr>
<tr>
<td class="fieldlabel">
Total Fixed Asset Value
</td>
<td class="fielddata">
#Html.EditorFor(model => model.TotalFixedAssetValue)
#Html.ValidationMessageFor(model => model.TotalFixedAssetValue)
</td>
</tr>
<tr>
<td class="fieldlabel">
Total Fixed Equipment Value
</td>
<td class="fielddata">
#Html.EditorFor(model => model.TotalFixedEquipValue)
#Html.ValidationMessageFor(model => model.TotalFixedEquipValue)
</td>
</tr>
<tr>
<td colspan="2">
<table class="display" style="text-align: center;">
<tr>
<td>
#Html.ActionLink("Add/Edit Spaces", "Index")
</td>
<td>
<input type="submit" value="Save Changes" class="button" />
</td>
<td>
#Html.ActionLink("Back to Buildings List", "Index")
</td>
</tr>
</table>
</td>
</tr>
</table>
}
When I click the back button from the Edit view I expected to see the WebGrid again (building list), but instead I get the first view without any CSS formatting.
Thanks to Luis I was able to resolve the CSS formatting issue, but I'm still not seeing the WebGrid when I click the back button. I'm using JSON to populate the WebGrid could this be the problem? Should I use a form post after the item in the dropdown has been selected?
Something similar happened to me making an app for the intranet... but hey cheer up, at least your company uses IE9... I had to make miracles trying to make a MVC3 Razor app with JQuery work with IE7...
Ok now to what's important, I had a similar issue with the cache of IE, it appears that the cache of this browser works "differently" from the normal-new-age browsers, you could try this:
Press F12 and go to the tab Cache and check Always refresh from server
Then check if everything works as it should do, if it does, tell your network administrator to make a new policy for all the IE browsers that are going to use this new app you're making.
Also check this https://superuser.com/questions/81182/how-to-force-internet-explorer-ie-to-really-reload-the-page
Hope it helps!
You need to add the Location to the attribute to get this to work with IE9
[OutputCache(Location = OutputCacheLocation.ServerAndClient, NoStore = true, Duration = 0, VaryByParam = "None")]

How to give names for dynamically generated radiobuttonfor

I am generating radiobuttonfor dynamically.
My code runs as,
#{int questionCount = 0;
}
#{foreach (SectionDetail sectionDetail in section.SectionDetails)
{
<table>
<tr>
<td>
#Html.Label(sectionDetail.Title)
</td>
#{count = 0;
}
#foreach (SectionScore sectionScore in Model.IndividualSections)
{
<td class="ColSupplier">
#Html.RadioButtonFor(model => model.IndividualSections[count].SectionScores[questionCount].score.pass, true)Pass
#Html.RadioButtonFor(model => model.IndividualSections[count].SectionScores[questionCount].score.pass, false)Fail
</td>
count++;
}
</tr>
</table>
questionCount++;
}
Here some radio buttons are having the same name. So I am unable to get the exact value. How to give different names for these radio buttons. Please help me in sorting this out.
Please try this
#(Html.RadioButtonFor(model => model.IndividualSections[count].SectionScores[questionCount].score.pass, true, new {#id=sectionDetail.Title + count.Tostring() }) ))
You can use HtmlAttributes to define unique IDs.
#Html.RadioButtonFor(model => model.IndividualSections[count].SectionScores[questionCount].score.pass, true, new { id= count.ToString()});
Hope this helps you.

mvc3 form for a IEnumerable

I have a model that I would like have a mass update page for, but am having trouble.
My ViewModel:
public class ApproveView
{
public IEnumerable<MyObject> ObjectList { get; set; }
}
In my view I have:
foreach (var item in Model.ObjectList)
{
<div>
<table class="form" width="100%">
<tr>
<td>#Html.LabelFor(model => item.Accurate)<br />
#Html.RadioButtonFor(model => item.Accurate, true) Yes
#Html.RadioButtonFor(model => item.Accurate, false) No
#Html.ValidationMessageFor(model => item.Accurate)
</td>
<td>
#Html.LabelFor(model => item.Comments)<br />
#Html.TextAreaFor(model => item.Comments)<br />
#Html.ValidationMessageFor(model => item.Comments)
</td>
</tr>
</table>
#Html.HiddenFor(model => item.ID)
#Html.HiddenFor(model => item.CreatedOn)
#Html.HiddenFor(model => item.CreatedBy)
#Html.HiddenFor(model => item.ModifiedOn)
#Html.HiddenFor(model => item.ModifiedBy)
<hr />
}
This loops over my objects and prints the form. The trouble is that all of the fields of the same type have the same name. So, for example, all of my radio buttons are connected and I can only select one.
how do I make the names for each field unique and associated with that object? Am I even on the right track or is there a better way to do this?
Check this post: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
You need to create editor for your entity.
Hope it helps.
You could also do it a bit more manually:
#{var count = 0;}
#foreach (var item in Model.ObjectList){
<div>
<table class="form">
<tr>
<td>#Html.Label("Accurate" + count, item.Accurate)<br />
#Html.RadioButton("AccurateTrue" + count, true) Yes
#Html.RadioButton("AccurateFalse" + count, false) No
#Html.ValidationMessage("ValidationAccurate" + count, item.Accurate)
</td>
<td>
#Html.Label("CommentsLabel" + count, item.Comments)<br />
#Html.TextArea("Comments" + count, item.Comments)<br />
#Html.ValidationMessage("ValidationComment" + count, item.Comments)
</td>
</tr>
</table>
#Html.Hidden("ID" + count, item.ID)
#Html.Hidden("CreatedOn" + count, item.CreatedOn)
#Html.Hidden("CreatedBy" + count, item.CreatedBy)
#Html.Hidden("ModifiedOn" + count, item.ModifiedOn)
#Html.Hidden("ModifiedBy" + count, item.ModifiedBy)
<hr />
#count++;
#}

Resources