views:

140

answers:

1

I have a view model for a business. This model conatains a view model for address, contact details and also an IEnumerable.

I use editor templates to display the checkboxes. The problem is when I'm on the edit action and post the form the categories come back as null. I have read a few similar questions but havent found a solution that seems to work.

I have looked into Custom model binders with no luck and currently I'm thinking I'm not displaying the right information in the Editor template. I know checkboxes need a hidden input to go with them and maybe my problem lays there?

BusinessViewModel

public class BusinessViewModel
    {

        public int? Id { get; set; }

        [UIHint("ContactDetailsEditorTemplate")]
        public ContactDetailsViewModel ContactDetailsViewModel { get; set; }

        [UIHint("CheckboxEditorTemplate")]
        public IEnumerable<CheckboxViewModel> Categories { get; set; }

    }

CheckboxViewModel

public class CheckboxViewModel
{
    public int CategoryId { get; set;}
    public string Description { get; set;}
    public bool Checked { get; set; }
}

CheckboxEditorTemplate

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<ViewModels.BuyWithConfidence.CheckboxViewModel>>" %>
<table class="aligncenter">
  <tr class="tRow left"><%
    var intBreakLine = 0;
    if (Model != null)
    {
      foreach (var category in Model)
  {
    if (intBreakLine >= 2)
    {
      intBreakLine = 0;%>
      </tr>
      <tr class="tRow left"><%
    }%>
      <td>           
        <%= Html.Hidden(string.Format("Categories[{0}].CategoryID", i), category.CategoryId) %>
        <%= Html.CheckBox(string.Format("Categories[{0}].Checked", i), category.Checked) %>
      </td>
      <td><%=category.Description%></td><%
    intBreakLine = intBreakLine + 1;
    i = i + 1;  
  }
    }%>                        
  </tr>
</table>

This is a snippet of what the template is producing:

<input id="Categories_Categories_0__CategoryID" name="Categories.Categories[0].CategoryID" type="hidden" value="1" />
        <input id="Categories_Categories_0__Checked" name="Categories.Categories[0].Checked" type="checkbox" value="true" /><input name="Categories.Categories[0].Checked" type="hidden" value="false" />
+1  A: 

Looks like you'd end up with 3 inputs all named as the CategoryId. Have you looked into using the .index trick for collection binding. Or, you could use the array[] notation.

<%= Html.Hidden("Categories.index", category.CategoryID) %>
<%= Html.Hidden(string.Format("Categories[{0}].CategoryID", category.CategoryID), category.CategoryID) %>
<%= Html.CheckBox(string.Format("Categories[{0}].Checked", category.CategoryID), category.Checked) %>

If the order will remain the same you can use for(int i...).

<%= Html.Hidden(string.Format("Categories[{0}].CategoryID", i), category.CategoryID) %>
<%= Html.CheckBox(string.Format("Categories[{0}].Checked", i), category.Checked) %>

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

dotjoe
I'm still getting null for the trader.categories when the post action is hit. I tried both the above and started i at 0
Andi
I've updated question with the html that it produces maybe you can spot something?
Andi
The resulting html should be named `Categories[69].*`. Why is it `Categories.Categories[69].*`? That would tell the binder to look for a property named Categories that has a collection named Categories.
dotjoe
I have used the code you stated above so I'm confused why it is doing it twice I've updated my code above to show thesnippet where it creates the checkboxes
Andi
It seems to prefix it because my BusinessViewModel has the enumerable called Categories which my check boxe view model sits within (see my question again) Thanks
Andi
weird. How to do render the template? `<% Html.RenderPartial("CheckboxEditorTemplate", Model.Categories); %>` I'm not sure what this `UIHint` attribute is...does it auto prefix all the input elements for you?
dotjoe
UIHint is new to MVC2 and is a way of informating .NET of which EditorTemplate to use (It's basically a partial though)
Andi
hmm...I haven't used templates yet. Maybe switch to the `Html.HiddenFor` and `Html.CheckBoxFor`.
dotjoe
Does CheckBoxFor use the same parameters I couldnt work out what it was meant to do different.
Andi
It creates the input name based on the linq expression. `Html.CheckBoxFor(m => m[i].Checked)`. It will name it correctly with the array notation. `Categories[i].Checked` I'm not sure if the double Categories prefix would still show up.
dotjoe