Complex Models and Partial Views - Model Binding Issue in ASP.NET MVC 3

Complex models and partial views - model binding issue in ASP.NET MVC 3

Instead of:

@Html.Partial("_SimplePartial", Model.Simple)

I would recommend you using Editor templates:

@model ComplexModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.Simple)
<input type="submit" value="Save" />
}

and then put the simple partial inside ~/Views/Shared/EditorTemplates/SimpleModel.cshtml or inside ~/Views/Home/EditorTemplates/SimpleModel.cshtml where Home is the name of your controller:

@model SimpleModel
@Html.LabelFor(model => model.Status)
@Html.EditorFor(model => model.Status)

Of course if you prefer to have the partial in some special location and not follow the conventions (why would you?) you could specify the location:

@Html.EditorFor(x => x.Simple, "~/Views/SomeUnexpectedLocation/_SimplePartial.cshtml")

then everything will come into place as expected.

ASP.NET MVC 3 complex model binding issue

I think what you are looking for is the binding of collections. This may help: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

MVC Complex model binding with inheritance, nested viewModels and partial views

The problem is with using partials. Each time you go into the a partial, the model context changes, so the inputs that Razor generates for you are not taking the full property path into account. For example, if you were to do the following in your main view:

@Html.EditorFor(m => m.TrainerVM.SomeProperty)

The resulting HTML would be akin to:

<input type="text" name="TrainerVM.SomeProperty" />

However, when using a partial, your helper would be called as:

@Html.EditorFor(m => m.SomeProperty)

And the resulting HTML would be akin to:

<input type="text" name="SomeProperty" />

Once this gets posted back, the modelbinder doesn't know that SomeProperty belongs to the TrainerVM instance so it can't determine where to bind the posted value, and you end up with nulls. To continue to use partials but side-step this problem, you'll need to pass a value for ViewData.TemplateInfo.HtmlFieldPrefix (which is used to properly prefix the names of all the fields in the partial):

@Html.Partial("PartialTrainer", Model.TrainerVM, new ViewDataDictionary(ViewData)
{
TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "TrainerVM" }
})

asp mvc partial view model binding

The problem is your post method [Bind(Include = "some property")]. Which means you specified the list of properties only included in the model object, Other properties are not included in the model object.

The problem is Binding model is a complex model

The data structure you are posting in your Ajax call is not representative of what is expected in your controller, try this:

requestData = {
BrandDto : {
BrandId: params.pk,
columnName: params.name,
newValue: params.value
}
};

Losing partial view model form values

Partial views are still technically views. You're unable to get the values from the partial just because it is inside of the main view's form.

Look into Editor Templates, they'll allow you to achieve what you're looking for.

More on that here

Polymorphic model binding / Complex Models

Here is a demo:

Index.cshtml(when select SmartPhone,use example.cshtml,when select Laptop,use example1.cshtml):

@model MainCont
@{
ViewData["Title"] = "Home Page";
}

<form asp-action="create" asp-controller="home" method="post">
<select id="select" name="select">
<option value="SmartPhone">SmartPhone </option>
<option value="Laptop">Laptop </option>
</select>
<div id="sample"></div>
<button type="submit">გაგზავნა</button>
</form>
@section scripts{
<script>
$(function () {
GetPartialView();
})
$("#select").change(function () {
GetPartialView();
})
function GetPartialView() {
$.ajax({
url: "/Test1/ReturnExample",
type: "POST",
data: {
select: $("#select").val()
},
success: function (data) {
$('#sample').html(data);
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
}

example.cshtml:

@model SmartPhone
@Html.TextBoxFor(model => model.imei)
@Html.TextBoxFor(model => model.screensize)

example1.cshtml:

@model Laptop
@Html.TextBoxFor(model => model.CPU)
@Html.TextBoxFor(model => model.GPu)

Controller:

public IActionResult Index()
{
return View(new MainCont());
}
public IActionResult ReturnExample(string select)
{
if (select == "SmartPhone")
{
return PartialView("~/Views/Test1/example.cshtml", new SmartPhone());
}
else {
return PartialView("~/Views/Test1/example1.cshtml", new Laptop());
}

}

Create Action in Home Controller:

[HttpPost]
public IActionResult Create([ModelBinder(typeof(DataBinder))]MainCont mainCont) {
return Ok();
}

DataBinder:

public class DataBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var model1 = new MainCont();

var select = bindingContext.ValueProvider.GetValue("select").FirstValue;
if (select == "SmartPhone")
{
var model2 = new SmartPhone();
model2.screensize = bindingContext.ValueProvider.GetValue("screensize").FirstValue;
model2.imei = bindingContext.ValueProvider.GetValue("imei").FirstValue;
model1.Device = model2;
}
else if (select == "Laptop")
{
var model2 = new Laptop();
model2.CPU = bindingContext.ValueProvider.GetValue("CPU").FirstValue;
model2.GPu = bindingContext.ValueProvider.GetValue("GPu").FirstValue;
model1.Device = model2;
}

bindingContext.Result = ModelBindingResult.Success(model1);

return Task.CompletedTask;
}
}

result:
Sample Image



Related Topics



Leave a reply



Submit