3

I have a parent view model (Let's call it ParentViewModel) which has a list of children view models (Let's call them ChildViewModel). Each child view model can be edited independently and I have a separate form which I display in a loop. This works brilliantly but I cannot work out how to post just the child model and ignore the parent.

This is my form:

@model ParentViewModel

...

@foreach (var child in Model.Children)
{
    @using (Html.BeginForm("_EditChild", "Admin", FormMethod.Post))
    {
        @Html.AntiForgeryToken()
        <div class="form-group">
            @Html.EditorFor(model => child.Content, new {htmlAttributes = new {@class = "form-control"}})
            @Html.ValidationMessageFor(model => child.Content, "", new {@class = "text-danger"})
        </div>
        <div class="form-group">
            <div class="col-md-12">
                <input type="submit" value="Create" class="btn btn-default new-post" />
            </div>
        </div>
    }
}

And this is the signature of my controller. It is expecting a type ChildViewModel which exists in ParentViewModel as a list.

[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _EditPost([Bind(Include = "")] ChildViewModel childViewModel)
{

}

The form works and submits BUT ChildViewModel is null when it reaches the submit controller. This is certainly because binding between the Form Post and the Action is not happening.

Three Value Logic
  • 1,102
  • 1
  • 15
  • 37
  • 1
    what is _EditChild in BeginForm call? – skalinkin Apr 04 '16 at 17:08
  • May be move @using higher? *@using...@foreach...** – Denis Bubnov Apr 04 '16 at 17:16
  • First you cannot generate form controls inside a `foreach` loop (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) for an explanation). But you can only post back one form at a time so having a form for each item makes no sense. Either generate all controls in one form so you can edit and post back all changes at once, or provide links to another page to edit your child items. –  Apr 04 '16 at 22:17

2 Answers2

4

I am afraid it is not possible to post the child model only , since the page can define one and only one model that is the parent model you have defined .

But you can solve your problem simply by posting the parent model and extracting the child model in the controller .

hdrdiab
  • 343
  • 1
  • 11
1

It is possible, just not intended by ASP.NET MVC. All you would have to do is remove the parent prefix from the name of your submitted inputs on the client side. Your input would probably look something like:

<input name="Children[0].SomeProperty" ../>

If your AdminController._EditChild action expects a ChildViewModel, then you'd just have to use javascript to rename the input to:

<input name="SomeProperty" ../>

and the model binder should build the ChildViewModel. Alternatively, you might also be able to solve it by creating a custom ValueProvider or ModelBinder that maps the inputs to a ChildViewModel even though it has the wrong prefix...although that would seem like an uglier hack to me than changing the input names. On that note, I would probably also update the IDs with javascript when updating the names just to keep them in sync, even though only the name is used for binding.

Note also, if you're not looping but simply want to submit a single child ViewModel of your model, you can just assign it to a variable:

@var childVM = Model.ChildProp;
@Html.HiddenFor(m => childVM.ID)

Notice m is disregarded in the property expression of HiddenFor. I think last time I did this the variable name had to match the action's parameter name so you would submit this to:

public ActionResult SomeAction(ChildViewModel childVM){ ... }

I'm currently trying to understand why this technique can't be combined with looping.

xr280xr
  • 12,621
  • 7
  • 81
  • 125