ASP.NET MVC Updating a list of objects on one form? (model binding to a list)
One thing i noticed is that your not rendering <input type="hidden" name='results.Index' value='<%= i %>' />
as phil Haacks article mentions is mandatory.
Switching to a different Modelbinder might do the trick too. I use the DataAnnotations model binder and with that i dont have to generate .Index
fields when binding to List
's.
Related videos on Youtube
Sergio
Updated on April 16, 2022Comments
-
Sergio about 2 years
Quick question regarding updating a list of items in asp.net mvc.
Basically I have an edit action method that returns a collection of objects (incidentally, the table structure of which looks as follows 'testID, assetID, Result' - a link table).
I basically want this items to be displayed one after another in a form and to be able to edit them. The form should post back and the modelbinder do its magic. But, its not that easy.
I have scoured the net and it seems the majority of the information about this stuff seems to be a little out of date. I've come across this post, which has not been updated in a long time, and this one which seems to suggest that you shouldn't bind to a already existing list for updating, and that there are problems when working with EF or Linq to Sql (which I am).
Is there an easy way to achieve what I want? Has the state of list model binding changed in the release version?
UPDATE - A little closer...
Here's my Edit method:
public ActionResult EditSurveyResults(Guid id) { var results = surveyRepository.GetSurveyResults(id); return PartialView("EditSurveyResults", results); }
And my form:
<div id="editSurveyResults"> <h2> EditSurveryResults</h2> <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %> <% using (Html.BeginForm()) {%> <fieldset> <legend>Results</legend> <% int i = 0; foreach (var result in Model) { %> <input type="hidden" name='results[<%= i %>].TestID' value='<%= result.TestID %>' /> <input type="hidden" name='results[<%= i %>].AssetID' value='<%= result.AssetID %>' /> <p> <%= result.Task.TaskName%> </p> <p> <label for="Result"> Result:</label> <input type="text" name='results[<%= i %>].Result' value='<%= result.Result %>' /> <%= Html.ValidationMessage("Result", "*")%> </p> <% i++; } %> <p> <input type="submit" value="Save" /> </p> </fieldset> <% } %>
And my Edit POST method:
[AcceptVerbs(HttpVerbs.Post)] public ActionResult EditSurveyResults(Guid id, IList<SurveyTestResult> results) { var oldValues = surveyRepository.GetSurveyResults(id); if (ModelState.IsValid) { UpdateModel(oldValues); surveyRepository.Save(); return Content("Done"); } else return PartialView("EditSurveyResults"); }
It's not complete of course, but it doesn't update anything in its current state. Am I missing a trick here? results is populated with the the updated entities so I'm not sure why its not updating...
UPDATE 2: So, Im starting to think that the model binder cant do stuff like this. So, I've resorted to doing things in a more hacky way. If anyone can spot a problem with this then please let me know. FYI - this form will be grabbed with AJAX so I dont return a view, rather a simple message. Here's the new code:
IList<SurveyTestResult> oldValues = surveyRepository.GetSurveyResults(id).ToList(); foreach (var result in SurveyTestResult) { //SurveyTestResult is the IList that comes down from the form. SurveyTestResult thisone = oldValues.Single(p => p.AssetID == result.AssetID && p.TestID == result.TestID); //update the old entity with the result from the new one thisone.Result = result.Result; }
And then I call Save on my repository.
Thanks in advance