Collecting complex children in an Asp.Net MVC 3 application?

I want to be able to update the model and all its collections of child objects in one view. I mentioned these examples: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx and http://blog.stevensanderson.com/2010/01/28/editing -a-variable-length-list-aspnet-mvc-2-style / .

For example, I have a Consultant object that has a collection of "WorkExperiences". All this in the Entity Framework model. In the view, the simple properties of the Consultant object are not a problem, but in the collection I canโ€™t get a text box to display. I tried following the examples in the links above, but it does not work. The problem is that in these examples the model is just a list (and not an object with a child list property). And also the model is again an EF model. And for some reason this does not work, as in these examples.

Just to make it simple, I tried to do something according to the example of Phil Haaks and just get a view to show the text box:

@for (int i = 0; i < Model.WorkExperiences.Count; i++) { Html.TextBoxFor(m => m.WorkExperiences[i].Name); } 

I tried to create a new WorkExperience object in the controller for the ViewModel:

  public ActionResult Create(int id) { Consultant consultant = _repository.GetConsultant(id); DetailsViewModel vm = new DetailsViewModel(); vm.WorkExperiences = consultant.WorkExperiences.ToList(); vm.WorkExperiences.Add(new WorkExperience()); return View(vm); } 

But the view does not display an empty text field for the WorkExperience Name property. If, on the other hand, I create a separate View just to add a new WorkExperience object, passing the new empty WorkExperience object as a model, this works great:

 @Html.EditorFor(model => model.Name) 

This gives me an empty text box and I can save the new object. But why can't I do this in the same view as the โ€œConsultantโ€ object, with the collections in accordance with the examples in the links above?

By the way, this is a kind of next question to the previous one, which pointed me to the links above, but I still have not received a final solution. See this question for more information: Create views for object properties in a model in an MVC 3 application

UPDATE:

According to the answers and comments below, here is an update with View and EditorTemplate:

View:

 @model Consultants.ViewModels.DetailsViewModel @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Add work experience", "CreateWorkExperience", new { id = ViewBag.Consultant.Id }) </p> <table> <tr> <th></th> <th> Name </th> </tr> @foreach (var item in Model.WorkExperiences) { <tr> <td> @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </td> <td> @item.Name </td> </tr> } </table> @for (int i = 0; i < Model. WorkExperiences.Count; i++) { Html.EditorFor(m => m. WorkExperiences[i]); } 

(Note that all this is actually not the way I will design it, all I want now is to make the WorkExperience object appear as an empty text field to fill in and be able to add and remove text fields such as in examples of Phil Haack and Stephen Sanderson.)

The EditorTemplate:

 @model Consultants.Models.WorkExperience @Html.TextBoxFor(m => m.Name); 

This stuff with EditorTemplate works fine in the sample sample project of Phil Haack, which I downloaded to try, but here, with the EF model or whatever problem, I don't get a text box at all. The table in the view is just like a test, because in the table I get rows for WorkExperiences, whether I add an empty WorkExperience object or fill in its properties, it does not matter, the rows are displayed for each object. But then again, there is no text box ...

+6
collections entity asp.net-mvc-3 entity-framework
source share
2 answers

For example, I have a Consultant object that has a collection of "WorkExperiences". All this in the Entity Framework model.

This is the first thing you need to improve: introduce view models and not use domain models in the view.

This allows you to go to the templates. This way you can completely eliminate the need to write loops in your views.

So what your view looks like:

 @model Consultants.ViewModels.DetailsViewModel @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Add work experience", "CreateWorkExperience", new { id = ViewBag.Consultant.Id }) </p> <table> <tr> <th></th> <th> Name </th> </tr> @Html.DisplayFor(x => x.WorkExperiences) </table> @Html.EditorFor(x.WorkExperiences) 

So, we can use the display template and the editor template. Now we define them.

Show template ( ~/Views/Shared/DisplayTemplates/WorkExperience.cshtml ):

 @model AppName.Models.WorkExperience <tr> <td> @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | @Html.ActionLink("Details", "Details", new { id = Model.Id }) | @Html.ActionLink("Delete", "Delete", new { id = Model.Id }) </td> <td> @Model.Name </td> </tr> 

Editor Template ( ~/Views/Shared/EditorTemplates/WorkExperience.cshtml ):

 @model AppName.Models.WorkExperience @Html.TextBoxFor(x => x.SomePropertyOfTheWorkExperienceModelYouWantToEdit) ... 

What is important here is the naming convention. The template name must be the type name of the item in the collection. For example, if in your view model you have a property

 public IEnumerable<Foo> { get; set; } 

the corresponding template should be called Foo.cshtml and should be in ~/Views/Shared/DisplayTemplates or ~/Views/Shared/EditorTemplates depending on its role.

So, as you can see, we got rid of unpleasant loops. Now, not only does the view look clean, but you get the correct names for the input fields so that you can bind the values โ€‹โ€‹in the post post.

+12
source share

The easiest way to do this is probably to create a WorkExperienceList class that inherits from List<WorkExperience> (or List<string> , if that's what they are), and then create your own template for your WorkExperienceList . This way you simplify your view code to @Html.EditorFor(Model) , and ASP.NET MVC takes care of you for the rest.

0
source share

All Articles