Nicholas Magnussen
Nicholas Magnussen

Reputation: 769

MVC Post with complex types, model is empty

I have the following code to fill my model before posting it to my controller. The list I'm iterating through is a list.

<div class="tab-content">
            @*@foreach (var description in Model.Category.C_CategoryDescription)*@
            @for (var i = 0; i < Model.Category.C_CategoryDescription.Count; i++)
            {
                <div id="@("tab" + @Model.Category.C_CategoryDescription.ToList()[i].ProductTypeId)" class="@(Model.Category.C_CategoryDescription.ToList()[i] == @Model.Category.C_CategoryDescription.First() ? "tab-active" : "tab")">
                    <div class="form-group ">
                        @Html.LabelFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionTop, "Beskrivelse - Top", htmlAttributes: new {@class = "control-label col-md-2"})
                        <div class="col-md-10">
                            @Html.TextAreaFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionTop, new {@class = "richText"})
                        </div>
                    </div>

                    <div class="form-group">
                        @Html.LabelFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionBottom, "Beskrivelse - Bund", htmlAttributes: new {@class = "control-label col-md-2"})
                        <div class="col-md-10">
                            @Html.TextAreaFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionBottom, new {@class = "richText"})
                        </div>
                    </div>
                </div>
            }
        </div>

The HTML comes out fine. But as soon as I catch the post in my controller, the model is empty. Not NULL, but empty. I read numerous articles saying that it points to a problem with the model binding.

I changed my code to reflect what's described: here

Still no dice. Any help is appreciated.

EDIT: I changed my code according to this post.

My view now looks like this:

<div class="tab-content">
            @Html.Partial("_Edit", Model.Category.C_CategoryDescription.ToList())
        </div>

With a partial view looking like this:

    @model IList<DataAccess.Plusbog.C_CategoryDescription>

@{
    var productType = Model;
}

@for (var i = 0; i < productType.Count; i++)
{
    <div id="@("tab" + @Model[i].ProductTypeId)" class="@(Model[i] == @Model.First() ? "tab-active" : "tab")">
        <div class="form-group ">
            @Html.LabelFor(model => productType[i].DescriptionTop, "Beskrivelse - Top", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => productType[i].DescriptionTop, new { @class = "richText" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => productType[i].DescriptionBottom, "Beskrivelse - Bund", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => productType[i].DescriptionBottom, new { @class = "richText" })
            </div>
        </div>
    </div>
}

Same result, sadly.

EDIT:

Here's the models:

public class CategoryModel
{
    public C_Category Category { get; set; }
    public SelectList Categories { get; set; }
    public SelectList ProductTypes { get; set; }
    public String ISBNListToAddManually { get; set; }
    public string Response { get; set; }
}

And the C_Category class:

public partial class C_Category
{
    public C_Category()
    {
        this.C_CategoryDescription = new HashSet<C_CategoryDescription>();
        this.Books = new HashSet<Books>();
        this.ChildCategories = new HashSet<C_Category>();
        this.Campaign = new HashSet<Campaign>();
        this.Group = new HashSet<Group>();
    }

    public int Id { get; set; }
    public Nullable<int> ParentCategoryId { get; set; }
    public string Name { get; set; }
    public bool Active { get; set; }
    public string Slug { get; set; }
    public string Keywords { get; set; }

    public virtual ICollection<C_CategoryDescription> C_CategoryDescription { get; set; }
    public virtual ICollection<Books> Books { get; set; }
    public virtual ICollection<C_Category> ChildCategories { get; set; }
    public virtual C_Category ParentCategory { get; set; }
    public virtual ICollection<Campaign> Campaign { get; set; }
    public virtual ICollection<Group> Group { get; set; }
}

And lastly, the C_CategoryDescription:

public partial class C_CategoryDescription
{
    public int CategoryId { get; set; }
    public int ProductTypeId { get; set; }
    public string DescriptionTop { get; set; }
    public string DescriptionBottom { get; set; }
    public string MetaDescription { get; set; }
    public string MetaKeywords { get; set; }
    public string AlternativeTitle { get; set; }

    public virtual C_Category C_Category { get; set; }
    public virtual C_ProductType C_ProductType { get; set; }
}

Upvotes: 0

Views: 240

Answers (1)

user3559349
user3559349

Reputation:

Your code for generating the elements in the collection needs to be

@Html.TextAreaFor(m => m.Category.C_CategoryDescription[i].DescriptionTop, new {@class = "richText"})

which will generate the correct name attributes

<textarea name="Category.C_CategoryDescription[0].DescriptionTo" ... />
<textarea name="Category.C_CategoryDescription[1].DescriptionTo" ... />

Your current use a .ToList() is generating incorrect name attributes (not tested, but I assume its name="[0].DescriptionTo")

Alternatively you can use a custom EditorTemplate for the C_CategoryDescription model if you cannot change the collection to implement IList

In Views/Shared/EditorTemplates/C_CategoryDescription.cshtml (note the name of the file must match the name of the class)

@model yourAssembly.C_CategoryDescription

<div class="form-group ">
    @Html.LabelFor(m => m.DescriptionTop, "Beskrivelse - Top", new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.TextAreaFor(m => m.DescriptionTop, new { @class = "richText" })
    <div>
</div>
....

and then in the main view, to generate the correct html for each item in the collection

@Html.EditorFor(m => m.Category.C_CategoryDescription)

Upvotes: 3

Related Questions