2

I have one scenario in my project like below.

Create Person with two views. One is parent view contains person names and the other is partial view contains address information.

if i click on submit button in parent view, i need to read the data entered in address partial view and pass it to PersonViewModel object for POST action method.

I am unable to AddressViewModel from POST Action method, getting null value. Anyone help me how to resolve this issue.

Thanks in advance.

Please find the sample code below.

ViewModels:

 public class PersonViewModel
 {
    public string FirstName{get;set;}
    public string LastName{get;set;}
    public AddressViewModel Address{get;set;}
 }

 public class AddressViewModel
 {
    public class Address1{get;set;}
    public class Address2{get;set;}
 }

PersonController

 public ActionResult POST(PersonViewModel model)
 {
    Person person=new Person();
    person.FirstName=model.FirstName;
    person.LastName=model.LastName;

    if(model.Address!=null)
    {
         person.Address1=model.Address.Address1;
    }

    return View("Confirmation");
 }

AddressController:

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

Person View:

@model POC.ViewModels.PersonViewModel

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
            </div>
        </div>
        <div>
        @{Html.RenderPartial("~/Views/Shared/_Address.cshtml");}
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>

}

Address Partial View:

@model POC.ViewModels.AddressViewModel
<div class="form-horizontal">

    <div class="form-group">
        @Html.LabelFor(model => model.Address1, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Address1, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Address1, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Address2, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Address2, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Address2, "", new { @class = "text-danger" })
        </div>
    </div>
</div>
ponnapureddy
  • 53
  • 1
  • 1
  • 8
  • Show how you are calling the partial in the view. –  May 06 '15 at 10:08
  • You need to show the view. If its not binding its because your view code is wrong! –  May 06 '15 at 10:57
  • @Hanu where is the view? – clement May 06 '15 at 11:09
  • @StephenMuecke, I have added views. Please review and suggest me. – ponnapureddy May 07 '15 at 06:35
  • You partial is generating controls with `name="Address1"` but your model does not include a property with the name `Address1` (only a property named `Address` which is a complex object containing a property named `Address1`. I will post an answer shortly with 2 options to fix this. –  May 07 '15 at 06:38
  • @StephenMuecke Thanks for the immediate response. The basic idea behind this i want use this Address partial view in other controllers for re usability purpose for GET, POST, PUT action methods for other controllers also. – ponnapureddy May 07 '15 at 06:46

2 Answers2

1

You partial is generating controls with name="Address1" and name="Address2" but your model does not include a property with the names Address1 and Address2 (only a property named Address which is a complex object containing properties Address1 and Address2. In order to bind to your model the name attributes would need to be name="Address.Address1" and name="Address.Address2".

The best way to solve this is to make your partial an EditorTemplate by renaming it to AddressViewModel.cshtml and placing it in the Views\Shared\EditorTemplates folder (or in the Views\YourControllerName\EditorTemplates folder, and then in the main view use

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

An alternative using a partial is to pass the prefix to the partial using addititional ViewData

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

This answer also includes an example of a html helper extension method that makes adding the prefix a little easier

Community
  • 1
  • 1
0

You need a form inside the view. Something like this:

@using (Html.BeginForm("POST")){
  @Html.EditorFor(m => m.FirstName)
  @Html.EditorFor(m => m.Address.Address1)
  <input type="submit"/>  
}

It is the act of submitting the form that creates the request. It is also important that you use either the helpers to create the input fields, or if you want to create them yourself, you create them with the correct names, e.g.:

<input type="text" name="Address.Address1"/>

Note the value of the name attribute, this is the value that the EditorFor will generate. This name is important so that the model binder will set the Address1 value in PersonViewModel.Address.Address1

If you render the Address with a partial view you'll have to make sure that the inputs have the correct names set. This is not a very good idea though because for all this to work the AddressViewModel property name in PersonViewModel must be Address, if you change its name to, for example MyAddress, you need to update the input's names to MyAddress.Address1, etc.

Rui
  • 4,847
  • 3
  • 29
  • 35
  • thanks for the suggestion. As you are suggestion in the view no need to add partial view, But if we want to read data from partial view and assign it to parent view model, how can i do that. Please suggest. – ponnapureddy May 06 '15 at 13:02
  • @Hanu, 3 time you have been asked to include the view in your question so that we can give you the correct answer. Don't ask us to guess what you are doing wrong! –  May 06 '15 at 14:19