Several forms in a complex representation model - how can I bind only one of them?

I have a complex view model that contains a collection of other objects that are displayed recursively using editor and display templates.

Each of the elements in the collection contains a form model that I would like to introduce to the controller. Please note that I do not want to publish the entire view model again, only the form model.

My problem is that MVC displays each object as part of a collection, and I don't know how to associate one object from a collection with an object in a controller signature.

I know that I can link the whole batch again using IEnumerable<Account> , but I'm trying to create row-level views, not the whole page.

If someone can point me in the right direction or show me how this should be done in the MVC world (I'm from web forms, so I was a bit messed up), I would really appreciate them.

I have included an example HTML snippet below, as well as a controller to which I would like to send a message.

 <form action="/Home/Index" method="post"> <input id="Accounts_0__AccountName" name="Accounts[0].AccountName" type="text" value="Account 1" /> <input id="Accounts_0__AccountId" name="Accounts[0].AccountId" type="hidden" value="dddf5ca7-f8de-4192-b63a-3548f891e293" /> <input type="submit" value="Submit" /> </form> <form action="/Home/Index" method="post"> <input name="Accounts[1].AccountName" type="text" value="Account 2" /> <input id="Accounts_1__AccountId" name="Accounts[1].AccountId" type="hidden" value="95d75f76-16ef-4cf2-b1e7-5fad782002c5" /> <input type="submit" value="Submit" /> </form> [HttpPost] public ActionResult Index(Account accounts) { ... } 
+4
source share
2 answers

You can try to set the prefix in the editor template:

 @model AppName.Models.Account @{ ViewData.TemplateInfo.HtmlFieldPrefix = string.Empty; } @using (Html.BeginForm("Index", "Home")) { @Html.TextBoxFor(x => x.AccountName) @Html.HiddenFor(x => x.AccountId) <input type="submit" value="Submit" /> } 

which, if I'm not mistaken, should generate:

 <form action="/Home/Index" method="post"> <input id="AccountName" name="AccountName" type="text" value="Account 1" /> <input id="AccountId" name="AccountId" type="hidden" value="dddf5ca7-f8de-4192-b63a-3548f891e293" /> <input type="submit" value="Submit" /> </form> 

Obviously, you understand that in doing so you get invalid HTML (you will have several elements with the same id ). A possible workaround would be to set the identifier manually:

 @Html.TextBoxFor(x => x.AccountName, new { id = "some unique value like a GUID" }) @Html.HiddenFor(x => x.AccountId, new { id = "some unique value like a GUID" }) 

Another possibility is to write a custom mediator for the type of account that simply ignores the prefix when binding.

+4
source

I solved the problem by adding a hidden field to the editor template that contains the account prefix and creates a custom middleware that uses the value of the hidden field as the model name. The default binder can then bind it as if it was a single form view, rather than a set of presentation models.

 @model MvcApplication1.Models.Account @using (Html.BeginForm("Submit", "Home")) { @Html.TextBoxFor(m => m.AccountName) @Html.HiddenFor(m => m.AccountId) @Html.ValidationMessageFor(m => m.AccountName) <input type="hidden" value="@ViewData.TemplateInfo.HtmlFieldPrefix" name="account.prefix" /> <input type="submit" value="Submit" /> } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { bindingContext.ModelName = controllerContext.HttpContext.Request.Form["account.prefix"]; return base.BindModel(controllerContext, bindingContext); } 
0
source

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


All Articles