AlexGH
AlexGH

Reputation: 2817

Pass complex object from view to Controller

I have this model:

public class MyClassVM
{
public Product MyProduct { get; set; }
public IEnumerable<Dog> MyDogs { get; set; }
}

Then I have this action in a controller:

[HttpPost]
public ActionResult MyAction(MyClassVM)
{
//do something...
}

I have an html view and have been for a while trying to bind the object and send it from the view to the controller as a parameter but I've not been able yet... Which is the correct way to do this?

 <form method="post" action="MyController/MyAction">


   @{ foreach (var dog in Model.MyDogs)
    <tr>
    <td><input type="checkbox" name="[@i].MyDogs" /></td>
    </tr>

}
    <input type="hidden" name="MyProduct" value="@Model.MyProduct"/>
    <input type="submit" value="Submit"/>
    </form>

But when it arrives to the controller is always null... I've checked the request using Dev Tools and the data is not being bound correctly. I would probably need to serialize the object to Json format in my view???

Upvotes: 2

Views: 3040

Answers (1)

user3559349
user3559349

Reputation:

You cannot bind a complex object to an <input>. Both post back a single value.

Your checkbox posts back "on" if its checked and nothing if its not (because it does not have a value attribute) which cannot be bound to typeof Dog. And if you inspect the value attribute for the hidden input you will see that it is value="yourAssembly.Product" which again cannot be bound to typeof Product.

You need to generate a form control for each property of each Dog in the collection, and a form control for each property of Product.

A typical example based on the following models

public class Dog
{
    public int ID { get; set; }
    public string Name{ get; set; }
    public bool IsSelected { get; set; }
}
public class Product
{
    public int ID { get; set; }
    public string Name{ get; set; }
}

View

@for(int i = 0; i < Model.MyDogs.Count; i++)
{
    @Html.HiddenFor(m => m.MyDogs[i].ID)
    @Html.CheckBoxFor(m => m.MyDogs[i].IsSelected)
    @Html.LabelFor(m => m.MyDogs[i].IsSelected, Model.MyDogs[i].Name)
}
@Html.HiddenFor(m => m.MyProduct.ID)
@Html.TextBoxFor(m => m.MyProduct.Name)

Note that your MyDogs needs to implement IList, otherwise you need to use an EditorTemplate for typeof Dog (refer Post an HTML Table to ADO.NET DataTable for more detail).

Note also that if your not editing any properties of Product, then do not include any form controls for it - just get the Product again in the POST method if you need it.

Upvotes: 2

Related Questions