1

I'm developing a web MVC application with net core 2.2.

I have the following classes:

public class A
{
    public IList<B> Bs { get; set; }
}

public class B
{
    public string Id { get; set; }
    public string Name { get; set; }
}

The following view:

@model A

@for (int i = 0; i < Model.Bs.Count; i++)
{
    <partial name="_BsPatialView" for="Bs[i]" />
}

And the following partial view (_BsPatialView.cshtml):

<input type='hidden' asp-for="@Model.Id" />
<input asp-for="@Model.Name" />

Until here, everything it-s been generated fine. An example of the created inputs in the partial view is:

  • <input type="hidden" id="Bs_3__Id" name="Bs[3].Id" />
  • <input type="text" id="Bs_3__Name" name="Bs[3].Name" />

With the elements name and ids the model binder in the controller can properly bind everything.

The problem is when I try to return the partial view from the controller. What I do is:

public IActionResult AddBElement(A a)
{
    a.Bs.Add(new B() { Id = Guid.NewGuid() });
    return PartialView("_BsPatialView", a.Bs.Last());
}

The resulting html is:

  • <input type="hidden" id="Id" name="Id" />
  • <input type="text" id="Name" name="Name" />

So then, when I submit a form in which these inputs are, the model binding fails.

So, how should I return the partial view from the controller to fix this? Is there any equivalent to the partial's tag helper for attribute to use on the controller?

joacoleza
  • 775
  • 1
  • 9
  • 26

1 Answers1

1

Model binding uses field names to map them to Model properties. Now because your name does not contain any information about the parent class, A, model binder does not know how to bind them.

So in other words, model binder would know how to bind this input:

<input type="hidden" id="Bs_3__Id" name="A.Bs[3].Id" />

But not this input:

<input type="hidden" id="Bs_3__Id" name="Bs[3].Id" />

One solution would be pass the prefix, A to the partial view: See this answer

A better solution would be to use EditorTemplate instead of Partial View, which would generate correct name for your input field. To use EditorTemplate Rename your partial view to B.cshtml (this should be your class name) and put it under /Views/Shared/EditorTemplates folder... then you can use it like this:

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

Check this tutorial for more info about Editor Templates

Also check this question, which is very similar to yours

Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
  • The thing is that I want to load that partial from the server and append it to the place where the other Bs are. Anyway, I have change the design to avoid this issue. Thanks for the answer! – joacoleza Apr 08 '19 at 23:00