barker1889
barker1889

Reputation: 37

MVC Populate a collection of items within a model

Im just starting to learn MVC 3 and i could do with some advice on the best way of achieving something.

I have a basic scenario where i can create a blog post with some text and a a collection of tag objects. Each blog can have multiple tags and each tag be attatched to multiple blogs.

public class BlogPost
{
    public int ID { get; set; }
    public string BlogText { get; set; }

    public virtual ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public int ID { get; set; }
    public string TagText { get; set; }

    public virtual ICollection<BlogPost> Blogs { get; set; }
}

This creates the 2 model tables with the join table as id expect.

Whats the best way to go about adding a section to the create view of the BlogPost model that will allow me to add, edit and delete a set of tags (like in the index view)?

My initial thought would be to use a partial view of the tag object passing through the Model.Tags property but it looks like the Model property is null. Is this a good way of doing it or is there a better way?


Ok, so the action to create the view is the standard one generated:

    // GET: /Blog/Create

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

The view code is as follows:

@model MVC_ManyToManyTest.Models.BlogPost

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>BlogPost</legend>

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

        <div id="HolderForPartialView">
            @Html.Partial("ViewUserControl1", Model.Tags);
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

the partial view created is:

@model IEnumerable<MVC_ManyToManyTest.Models.Tag>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            TagText
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.TagText)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>

My Problem

Once I load the partial view i get the null reference at this line:

@Html.Partial("ViewUserControl1", Model.Tags);

the Model object is null

Upvotes: 0

Views: 4510

Answers (2)

Yasser Shaikh
Yasser Shaikh

Reputation: 47774

What I feel your code should be like is this,

public class MainModel
{
  public BlogPost MyBlogPost {get; set;}
  public Tags MyTags {get; set;}
}

First View

@model MVC_ManyToManyTest.Models.MainModel

// Use model.MyBlogPost.variables here
...

@Html.Partial("ViewUserControl1", Model.Tags);

....

Partial View

@model IEnumerable<MVC_ManyToManyTest.Models.Tag>

// Use model.MyTags.variables here
...

I am not very sure about this, but I once had a similar problem which I had solved using this. Hope this helps.

Upvotes: 0

Jerad Rose
Jerad Rose

Reputation: 15513

The Model is null because your action method is not sending one in:

return View();

You need to give it an empty model with an empty collection of Tags. Something like:

var model = new BlogPost { Tags = new Collection<Tag>() };
return View(model);

Alternatively, you can also make the creation of empty collections as part of your model constructor:

public class BlogPost
{
    public BlogPost()
    {
        this.Tags = new Collection<Tag>();
    }

    public int ID { get; set; }
    public string BlogText { get; set; }

    public virtual ICollection<Tag> Tags { get; set; }
}

Upvotes: 2

Related Questions