How to handle the binding prefix of an MVC model with the same shape repeated for each row in the collection?

My main view model has a ChildViewModel collection. In the view, I iterate over the collection and call EditorFor (), for example:

@for (int i = 0; i < Model.Children.Count; i++) { @Html.EditorFor(m => m.Child[i]); } 

The editor template looks like this:

 @model ChildModel @using (Html.BeginForm("EditChild", "MyController")) { @Html.HiddenFor(m => m.ChildId) @Html.TextBoxFor(m => m.ChildName) } 

This will create markup where each child will be in a separate form, and each such form will have an input control named Child [0] .ChildName. I use a separate form for each child, as the children will be displayed one on each line, and then the user can edit and send one line.

My form action method:

 [HttpPost] public ActionResult EditChild(ChildViewModel form) { } 

The problem is that when this is called, all the properties of the model will be empty, because the connecting device does not know about the prefix. In some situations, we can use BindAttribute to inform the model binding of the prefix, but in this case the prefix is ​​not constant: it will be Child [0], Child [1], etc.

So, we want to repeat the same form for each row in the collection, and then allow the POST user one form. How can a website handle the identifier, name, prefix, and model binding in this scenario?

+3
source share
1 answer

I have the same problem with you, and there is my solution, I hope this can help you.

add hidden input to your EditorTemplate or Partial View template

 <input type="hidden" name="__prefix" value="@ViewData.TemplateInfo.HtmlFieldPrefix" /> 

Define custom model bindings and override the BindModel method

 public class CustomModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var prefixValue = bindingContext.ValueProvider.GetValue("__prefix"); if (prefixValue != null) { var prefix = (String)prefixValue.ConvertTo(typeof(String)); if (!String.IsNullOrEmpty(prefix) && !bindingContext.ModelName.StartsWith(prefix)) { if (String.IsNullOrEmpty(bindingContext.ModelName)) { bindingContext.ModelName = prefix; } else { bindingContext.ModelName = prefix + "." + bindingContext.ModelName; // fall back if (bindingContext.FallbackToEmptyPrefix && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) { bindingContext.ModelName = prefix; } } } } return base.BindModel(controllerContext, bindingContext); } } 

The model linker truncates the prefix and makes model binding the default.

+5
source

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


All Articles