2

I have a complex model class like:

public class Client
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string AddressLine { get; set; }
}

My View is made of several Partial's on which I pass parts of the model into them and dispose some fields for edition:

In Index.cshtml

@using (Html.BeginForm("Index"))
{
    @Html.DisplayNameFor(modelItem => model.Name)
    @Html.DisplayFor(modelItem => model.Name)
    <div id="divAddress">
        @Html.Action("_Address", model.Address)
    </div>
    <div>RESULT MESSAGE GOES HERE!</div>
    <input type="submit" value="Submit" />
}

In _Address.cshtml

@Html.DisplayNameFor(modelItem => model.AdressLine)
@Html.EditorFor(modelItem => model.AdressLine)                      

On the code-behind my Actions consist of two simple ActionResults methods:

[HttpGet]
public ActionResult Index()
{
    Client = new Client();
    Client.Name = "António Fonseca"
    return View(model);
}

[HttpPost]      
public ActionResult Index(Client model)
{
    return View(model);
}

public ActionResult _Address(Address model)
{
    return View(model);
}

When I submit the form, I need to call a WebService with the full Client structure and display it's resulting message. What happens is that when hitting Index(model) -> model.Address is null. It's only bound back when it hits _Address(model) method.

Is there a way to bind the full class structure in main Action using PartialViews?

1 Answers1

1

Change the model in _Address.cshtml to be the same as the model in your main view and use @Html.Action("_Address", model) so that the form controls are correctly named - i.e. name="Address.AdressLine" (its currently just name="AdressLine" but you model does not contain a property named AdressLine).

@model Client
@Html.DisplayNameFor(m => m.Address.AdressLine)
@Html.EditorFor( m=> m.Address.AdressLine) 

However using @Html.Action() is not the correct approach for this. You should be using an EditorTemplate. Rename _Address.cshtml to Address.cshtml (to match the name of your class name) and place it in the /Views/Shared/EditorTemplates folder and then in the view use

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

which will correctly name your form controls.

  • What if I want to use the PartialView (and it's Model) in another View? For instance, a Company may too have an Address. I'm kind of new to this MVC paradigm. – user3466681 Oct 23 '15 at 23:49
  • If the partial is in the `/Views/Shared/EditorTemplates` folder and is named to match the class, then you can use it an any view. So if you had another class say `public class Organisation { public Address PostalAddress { get; set; }}` and then in a view for `Organisation` you would just use `@Html.EditorFor(m => m.PostalAddress)` - that's the benefit of using `EditorTemplates` –  Oct 23 '15 at 23:58
  • 1
    And another benefit is that you could have a property say `List
    OptionalAddress` and then `@Html.EditorFor(m => m.OptionalAddresses) will generate one template for each item in your collection and correctly name the form controls with indexers so they can be bound to your collection when you submit the form
    –  Oct 24 '15 at 00:03