1

I have problem when I am trying to pass values back from my page which contains the same partial view twice. My class definiton is like below:

public class Account : IEntity
{

    public decimal CurrentBalance { get; set; }
    public List<Person> AccountHolders { get; set; }
    //to get round the non-existing enum support in EF4.3 wrap enum to int
    public int StatusValue { get; set; }
    public AccountStatus Status { get { return (AccountStatus)StatusValue; } set { StatusValue = (int) value; } }

    public DateTime AccountOpenDate { get; set; }
    public DateTime AccountCloseDate { get; set; }
    public DateTime AccountSuspensionDate { get; set; }
    }

It has a List of Person , which I made a partial view for (for a single one).

<fieldset>
    <legend>Person</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>
      <div class="editor-label">
        @Html.LabelFor(model => model.Age)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Age)
        @Html.ValidationMessageFor(model => model.Age)
    </div>
</fieldset>

In the Create page for the Account I include 2 of the partial views I created as below.

 <div id="Person1">
        @Html.Partial("_CreateAccountHolder" )
    </div>

     <div id="Person2">
        @Html.Partial("_CreateAccountHolder")
    </div>

When I look at what is posted back, it contains the values (Name and Age as the properties of Person) I put in the form values of the page and I have have the tow of them as expected: CurrentBalance=19&Status=Closed&AccountOpenDate=12%2F12%2F2012&Name=mustafa&Age=20&Name=sofia&Age=20&AccountCloseDate=12%2F12%2F2012&AccountSuspensionDate=12%2F12%2F2012

But when I look at my create method on my controller I see the AccountHolder list as null. I tried with various signatures... public ActionResult Create(Account personalaccount, Person [] accountHolders) public ActionResult Create(Account personalaccount, List accountHolders)

If I only have one partial view of Person and have my controller like this, I can see the Person object bound correctly. public ActionResult Create(Account personalaccount, Person accountHolder)

Any ideas as to where I am going wrong?

tereško
  • 58,060
  • 25
  • 98
  • 150
Mustafa
  • 176
  • 3
  • 13

3 Answers3

2

If I understand your scenario correctly one way to accomplish this is to use Editor Templates instead of partial views. I have a little write up about them here:

codenodes.wordpress.com - MVC3 Editor Templates

To create an Editor Template:

  • if you don't already have a folder called "EditorTemplates" in the web project of your solution then create one in the Views\Shared folder.
  • add a new partial view and name it the same as the model you're rendering, in your case Person, so you would call it Person.cshtml (I know partial views are supposed to start with an underscore "_" but for an Editor Template it needs to be named the same as the model).
  • paste the code from your "_CreateAccountHolder" partial view into the new Person.cshtml Editor Template.
  • in your Create page render your AccountHolders list thusly:
<div id="People">
    @Html.EditorFor(x => x.AccountHolders)
</div>

If you need to have individual divs around each Person then you can add these to your Editor Template. The good thing about Editor Templates is that you only need a single call to the template even if you have multiple Person objects in your list - no need to loop or anything like that as the template automatically renders each Person object. It also names the field correctly so it should post back something like this if for example you have 2 Person objects in your collection:

AccountHolders[0].Name
AccountHolders[0].Age
AccountHolders[1].Name
AccountHolders[1].Age

Here's the code for your Editor Template:

@model Person

<fieldset>
    <legend>Person</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>
      <div class="editor-label">
        @Html.LabelFor(model => model.Age)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Age)
        @Html.ValidationMessageFor(model => model.Age)
    </div>
</fieldset>
Ciarán Bruen
  • 5,221
  • 13
  • 59
  • 69
0

First you should create CreateAccountModel with two instances of AccountModel, something like:

public class CreateAccountModel
{
    public Account Person1 { get; set; }
    public Account Person2 { get; set; }
}

Next, when you add your partial views, you should pass individual models to them, e.g:

<div id="Person1">
    @Html.Partial("_CreateAccountHolder", Model.Person1)
</div>

 <div id="Person2">
    @Html.Partial("_CreateAccountHolder", Model.Person2)
</div>

Now MVC will automatically prefix all account fields with PersonX, so all fields will be unique.

Alternatively you can specify prefixes manually when you add your partial views:

{
    var prefixData = new ViewDataDictionary { TemplateInfo = { HtmlFieldPrefix = "Person1" } };
    Html.RenderPartial("_CreateAccountHolder", new ViewDataDictionary(prefixData));
}
Shagglez
  • 1,522
  • 3
  • 21
  • 38
0

I understood my problem after reading [http://stackoverflow.com/questions/653514/asp-net-mvc-model-binding-an-ilist-parameter][1] Putting 2 partial views of the same type made the view return Name and Age pair with nothing to distingusih between the first and the second pair. I changed the parial view as below, but dont really like it...

    <div class="editor-field">
         @Html.TextBox("person[0].Name", "") 
        @Html.ValidationMessageFor(model => model.Name)
    </div>

    <div class="editor-field">
         @Html.TextBox("person[0].Age", "") 
        @Html.ValidationMessageFor(model => model.Age)
    </div>

    <div class="editor-field">
         @Html.TextBox("person[1].Name", "") 
        @Html.ValidationMessageFor(model => model.Name)
    </div>
    <div class="editor-field">
         @Html.TextBox("person[1].Age", "") 
        @Html.ValidationMessageFor(model => model.Age)
    </div>

It now postbacks something like below and I can read the IList in my controller..

CurrentBalance=19&Status=Closed&AccountOpenDate=12%2F12%2F2012&person%5B0%5D.Name=mustafa&person%5B0%5D.Age=19&person%5B1%5D.Name=sofia&person%5B1%5D.Age=20&AccountCloseDate=10%2F10%2F2012&AccountSuspensionDate=12%2F12%2F2012

Mustafa
  • 176
  • 3
  • 13