1

I have a 'Ticket' View with a partial View of "Comments". A Ticket can have many comments. I want to create a partial view of Comments inside the Ticket view so that I can add paging functionality to the Comments without impacting the ticket view. (I'll have 2 other partials with same functionality pertaining to different data but that are associated with the Ticket) I'm attempting to use the PagedList library available via Nuget.

In theory, I pass the ticket model to the GetComments controller where I search ticket comments comparing the ticketId's. I return a ToPagedList of Comments to the partial view. I want the paging to work within the partial view and with the GetComments controller. (I'd like to leave the 'Details' controller of Tickets with 'out of the box' functionality. e.g. return View(db.tickets.find(id))

I've never implemented a partial before, this is my 4th week learning MVC so any help is appreciated!

Parent View: TicketDetails.cshtml

 @model  DearSanta.Models.Ticket
  //ticket display markup removed to simplify

 // Where I wan my partial view of comments
 <div class="col-md-4">        
    @Html.Partial("GetComments", Model)
</div>

Partial View: GetComments.cshtml

@model  IPagedList<DearSanta.Models.TicketComment>
@using PagedList;

@section CSS{
 <link href="~/Content/PagedList.css" rel="stylesheet" type="text/css">
}


<div id="comments">
  <h4 class="title">Ticket Comments</h4>

  <ul class="timeline">
    @foreach (var c in Model)
    {

        <li>
            <i class="fa fa-comment"></i>
            <span class="date">@c.CreateDate.ToString("d MMM")</span>
            <div class="content">
                <p><strong>@c.User.DisplayName</strong> @c.Comment</p>
                <small>@Convert.ToInt32(((DateTime.Now -   c.CreateDate).TotalDays)) days ago</small>
            </div>
        </li>

    }
  </ul>
  <div>
    Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of  @Model.PageCount
    @Html.PagedListPager(Model, page => Url.Action("GetComments","Tickets",  new { page }))
 </div>
</div>

Partial View Controller:

         //Controller references: using PagedList;
                                  using PagedList.Mvc;


 public PartialViewResult GetComments(Ticket model, int page = 1)
    {
        int pageSize = 3; 

        var comments = db.TicketComment.Where(c => c.TicketId == model.TicketId).ToPagedList(page, pageSize);

        return PartialView("GetComments", comments);
    }
JReam
  • 888
  • 2
  • 11
  • 27

2 Answers2

1

@Html.Partial() renders a view - it does't pass trough a controller. It is most often used for static content. If you need to pass trough the controller you should use @Html.Action().

Note that the code you have will try to render the partial view passing it "DearSanta.Models.Ticket" although your partial expects "IPagedList< DearSanta.Models.TicketComment >".

See here for more detailed difference between @Html.Partial() and @Html.Action.

Community
  • 1
  • 1
  • This solution resolves the partial rendering of a partial view with its own controller, thank you. – JReam May 09 '15 at 16:34
0

I'd like to point out that there were two issues with my problem.

The first issue was that I was not using @HTML.Action as Dzhenko pointed out. This resolve the use of injecting a partial view with its own controller that I could pass something to (be it an object or a value etc).

The second issue I encountered for this problem is that my @Html.PagedListPager was not making Ajax calls. This was causing my entire page to reload with just the partial. Therefore I changed my code to the following, which now produces a parent view with a partial view that is pageable with paging only applicable to the partial.

Parent View:

@model  DearSanta.Models.Ticket
     //ticket display markup removed to simplify

    // Where I wan my partial view of comments
 <div class="col-md-4">        
     @Html.Action("GetComments", new { ticketId = Model.TicketId })
</div>

Partial View:

@model  PagedList.IPagedList<DearSanta.Models.TicketComment>
@using PagedList.Mvc;

@section CSS{
    <link href="~/Content/PagedList.css" rel="stylesheet" type="text/css">
}


<div id="comments">
    <h4 class="title">Ticket Comments</h4>

    <ul class="timeline">
        @foreach (var c in Model)
        {

            <li>
                <i class="fa fa-comment"></i>
                <span class="date">@c.CreateDate.ToString("d MMM")</span>
                <div class="content">
                    <p><strong>@c.User.DisplayName</strong> @c.Comment</p>
                    <small>@Convert.ToInt32(((DateTime.Now - c.CreateDate).TotalDays)) days ago</small>
                </div>
            </li>

        }
    </ul>
    <div>
        Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
        @Html.PagedListPager(Model, 
                                page => Url.Action("GetComments", new { ViewBag.ticketId, page }), 
                                PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions(){  HttpMethod = "GET", UpdateTargetId = "comments"})
                             )
    </div>
</div>

Controller for Partial View:

public PartialViewResult GetComments(int? ticketId, int page = 1)
        {
            int pageSize = 3;

            var comments =  (from c in db.TicketComment
                                where c.TicketId == ticketId
                                orderby c.CreateDate descending
                                select c).ToPagedList(page, pageSize);

            ViewBag.ticketId = ticketId;

            return PartialView("GetComments", comments);
        }

I hope that someone may find this solution helpful in the future. This is my second post with an answer. I'm starting to be able to give vs take always taking from the SO community hip hip horray!! ;)

Shout out to Troy for the sweet plugin!

JReam
  • 888
  • 2
  • 11
  • 27