How to configure a ViewModel and Partial Page to include an IEnumerable

310 views Asked by At

I'm trying to change my ASP.NET MVC project from straight Views and Models to using a ViewModel intermediate layer. Basically, what I'm doing includes having a Person with zero or more Events associated to them. I'm changing to the ViewModel because I want to put a partial view on the Person Details page that shows all of the associated Events.

I have a Person model class and one for Event, and this is my ViewModel:

public class PersonEventViewModel
{
    public PersonEventViewModel(Person person)
    {
        Person = person;
    }

    public Person Person { get; set; }
    public IEnumerable<Event> Events { get; set; }

}

This worked fine for converting my single record pages. On pages such as Person Details, I had to change lines like @Html.DisplayFor(model => model.CreatedOn) to @Html.DisplayFor(model => model.Person.CreatedOn) so it would find the properties correctly, but it worked. On the partial view I'm trying to make, however, I can't seem to get them to show the properties of the model in there. It looks more or less like this:

@model IEnumerable<Proj.ViewModels.PersonEventViewModel>

<table class="table">
    <tr>
        <th>@Html.DisplayNameFor(model => model.RecordedOn)</th>
        <th>@Html.DisplayNameFor(model => model.RecordedBy)</th>
        <th>@Html.DisplayNameFor(model => model.Comments)</th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>@Html.DisplayFor(modelItem => item.RecordedOn)</td>
        <td>@Html.DisplayFor(modelItem => item.RecordedBy)</td>
        <td>@Html.DisplayFor(modelItem => item.Comments)</td>
    </tr>
}

This worked when it was using the Events model directly, but now it doesn't seem to matter what I put in between model and the property, it always tells me that it can't resolve it.

Also, I'm not sure how to pass the ViewModel to the partial view. I haven't yet figured out what to put here:

@Html.RenderPartial("_PersonEventList", ?????)

My various attempts to pass the model or model info have all been met with errors.


Per request, this is the source of my details page, where I'm attempting to put the partial view of the Events.

@model Proj.ViewModels.PersonEventViewModel
@{ ViewBag.Title = "Details"; }
<h2>Details</h2>
<div>
    <h4>Person</h4> <hr/>
    <dl class="dl-horizontal">
        <dt>@Html.DisplayNameFor(model => model.Person.FirstName)</dt>
        <dd>@Html.DisplayFor(model => model.Person.FirstName)</dd>
        @*...and so on through the fields...*@
    </dl>
</div>
<p> @Html.ActionLink("Edit Record", "Edit", new {id = Model.Person.PersonId}) </p>

@Html.RenderPartial("_PersonEventList", Model)
2

There are 2 answers

4
Barry Franklin On

Assuming you want "events" in your partial, the partial should take a List<Event> as it's model:

@model IEnumerable<Event> (or List<Event>)

Then in your main view:

@Html.RenderPartial("_PersonEventList", Model.Events)
7
The Pax Bisonica On

As @Barry Franklin stated, you should change your partial to accept a list of Events. Another thing I wanted to mention is that you should probably be using Partial and not RenderPartial. RenderPartial needs to be encased in brackets and have a ; at the end of it in order for it to work (Html.Partial vs Html.RenderPartial & Html.Action vs Html.RenderAction).

@Html.Partial("_PersonEventList", Model.Events)

You also need to update the partial code:

    @model IEnumerable<Proj.ViewModels.Event>

<table class="table">
@foreach (var item in Model) {
    <tr>
        <td>@Html.DisplayFor(modelItem => item.RecordedOn)</td>
        <td>@Html.DisplayFor(modelItem => item.RecordedBy)</td>
        <td>@Html.DisplayFor(modelItem => item.Comments)</td>
    </tr>
}