ASP.Net MVC4 associates “create view” with a model that contains a list

I welcome you on the Internet, I have an interesting puzzle for you:

Is it possible to link a view to create an object if this object contains a list of other objects using exclusively MVC / partial views?

The person who got everything complicated is like ... let me give you a quick code example, which I mean:

Models: public class ComplexObject { public string title { get; set; } public List<ContainedObject> contents { get; set; } } public class ContainedObject { public string name { get; set; } public string data { get; set; } } 

Nice and easy? Ok, so a strongly typed view to create one of them is really simple for the title property:

 something like: @Html.TextBoxFor(x => x.title) 

but I cannot find a good way to link the "ContainedObjects" list using MVC. The closest I got is to create a strongly typed partial IEnumerable view with a List forest template and include it on the page.

Without adding style, etc. By default, this partial view is as follows:

 @model IEnumerable<MVCComplexObjects.Models.ContainedObject> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> @Html.DisplayNameFor(model => model.name) </th> <th> @Html.DisplayNameFor(model => model.data) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.name) </td> <td> @Html.DisplayFor(modelItem => item.data) </td> <td> @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) | @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) | @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ }) </td> </tr> } </table> 

But to be honest, I can't figure out how to enable this as related to creating a new ComplexObject. In other words, I can show a list of existing ContainedObjects by tying them like this: @ Html.Partial ("PartialCreate", Model.contents)

But I really want, I think, something like:

 @Html.PartialFor("PartialCreate", x => x.contents) 

I should note that I did not have too many problems encoding around this with Javascript (I will include this code below), but I would really like to know if there is a way to do this exclusively with MVC. I am a recent converter from WebForms (where I would just replace all my callbacks with AJAX calls anyway), and a lot of things come up in the projects I'm working on.

Anyway, here's how I do it now:

Html -

 Name: <input type="text" id="enterName" /> Data: <input type="text" id="enterData" /> <a id="addItem">Add Item</a> <ul id="addedItems"> </ul> <a id="saveAll">Save Complex Object</a> 

Javascript -

 <script> var contents = []; $(document).ready(function () { $('#addItem').click(function () { var newItem = { name: $('#enterName').val(), data: $('#enterData').val() }; contents.push(newItem); $('#addedItems').html(''); for (var i = 0; i < contents.length; i++) { $('#addedItems').append( "<li>" + contents[i].name + ", " + contents[i].data + "</li>" ); } }); $('#saveAll').click(function () { var toPost = { title: "someTitle", contents: contents }; $.ajax({ url: '/Home/SaveNew', type: 'POST', data: JSON.stringify(toPost), dataType: 'json', contentType: 'application/json; charset=utf-8', success: function (data, textStatus, jqXHR) { alert("win"); }, error: function (objAJAXRequest, strError) { alert("fail"); } }); }); }); </script> 

And this is not a scary decision or something else, I just don’t want to make Javascript calls every time I want to save a new object, but I use standard Razr code everywhere. I would like to be consistent enough in all directions.

Does anyone else run into this problem and find a solution?

+4
source share
2 answers

Recently, it seemed to me that I needed to perform the same task and, like you, not wanting to add a bunch of javascript. I use MVC4, and as far as I can tell, there is no ready-made way to bind the enumerable properties of the model to the view. :(

However, as you demonstrated in your question, it is possible to get enumerable properties from a model in a view. The trick just returns updates to the controller. Based on your sample models, your view may look like this (you do not need to do partial):

 @model MVCComplexObjects.Models.ComplexObject <p> @Html.ActionLink("Create New", "Create") </p> @using (Html.BeginForm("SaveNew", "Home", FormMethod.Post)) { <table> <tr> <th> @Html.DisplayNameFor(model => model.contents[0].name) </th> <th> @Html.DisplayNameFor(model => model.contents[0].data) </th> <th></th> </tr> @for (int i = 0; i < Model.contents.Count; i++) { <tr> <td> @Html.TextBox("updatedContents["+i+"].name", Model.contents[i].name) </td> <td> @Html.TextBox("updatedContents["+i+"].data", Model.contents[i].data) </td> <td> @* Got rid of the edit and detail links here because this form can now act as both *@ @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ }) </td> </tr> } </table> <input type="submit" value="Save" /> } 

And your controller action will look like this:

 [HttpPost] public ActionResult SaveNew(ICollection<ContainedObject> updatedContents) { foreach (var co in updatedContents) { //Update the contained object... } return RedirectToAction("Index"); } 

Basically, we define a new collection object in the MVC view to jump to your action method when submitting the form. The new object ("updatedContents" in this example) is basically the same as the list property ("content" in this example) that was defined and populated in the ComplexObject model.

This is a bit more work, but to achieve the goal you do not need any javascript for the message. Everything can be done with standard MVC.

+1
source

Source: https://habr.com/ru/post/1440781/


All Articles