I'm doing comment pagination of product in ASP NET CORE using Ajax . I use code from ASP.Net Core how to add ajax pagination? to apply in my code. I change the code to suitable in my context. In the product detail page I use partial view. This is the product detail page and javascript
<div id="table1" class="col-md-6">
<partial name="_Comment" model="@Model.ProductItems.Product.ProductComments.ToPagedList()" />
</div>
///javascript
$(function () {
function interceptPaging() {
$("#table1").on("click", ".pagination a", function (event) {
event.preventDefault();
$.get($(this).attr("href"), function (data) {
$("#table1").html(data);
interceptPaging();
});
});
}
interceptPaging();
});
The partial view:
@using X.PagedList;
@using X.PagedList.Mvc.Core
@model X.PagedList.IPagedList<Laptop.Models.ProductComment>
<div id="reviews">
<ul class="reviews">
@foreach (var comment in Model)
{
<li>
<div class="review-heading">
<h5 class="name">@comment.Customer.UserName</h5>
<p class="date">@comment.CreateDate</p>
<div class="review-rating">
@for (int i = 1; i <= 5; i++)
{
<i class="fa fa-star@(comment.Ratings >= i ? "" : "-o")"></i>
}
</div>
</div>
<div class="review-body">
<p>@comment.Detail</p>
</div>
</li>
}
</ul>
</div>
<div class="pagination">
@(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) Comments @Model.PageCount
@Html.PagedListPager(Model, page => Url.Action("ProductDetail ", "ProductView", new { page }))
</div>
In the controller :
public async Task<IActionResult> ProductDetail(int? id, int? page)
{
if (id == null)
{
return BadRequest();
}
var sp = await _context.ProductVariations
.Include(n => n.ProductItems.Product.ProductComments)
.ThenInclude(n => n.Customer)
.Include(n => n.ProductItems.Product.Category)
.Include(n => n.Ram)
.Include(n => n.Ssd)
.FirstOrDefaultAsync(n => n.ProductVarId == id);
ViewBag.Comment = await _context.ProductComments
.Where(n => n.ProductId == sp.ProductItems.ProductId)
.ToListAsync();
var items = _context.ProductComments.Where(n => n.ProductId == sp.ProductItems.ProductId).OrderBy(c => c.CreateDate).ToPagedList(page ?? 1, 3);
var isAjax = Request.Headers["X-Requested-With"] == "XMLHttpRequest";
if (isAjax)
{
return PartialView("_Comment", items);
}
ViewBag.ListSP = _context.ProductVariations
.Where(n => n.ProductItemsId == sp.ProductItemsId && n.ProductVarId != id)
.Include(n => n.ProductItems)
.Include(n => n.Ram)
.Include(n => n.Ssd)
.Include(n => n.ProductItems.Product.Category)
.ToList();
if (sp == null)
{
return NotFound();
}
return View(sp);
}
On the website, the list comment shows up but only show the blue small box example not the pagination. I have tried many ways but still doesn't work. Anyone know what is the problem? I really appreciated any instruction. Thank you for reading.
Even though you're following this code there are certain changes in your code that break pagination.
The main reason why pagination does not work in your example is that you're passing the wrong model to the partial view:
<partial name="_Comment" model="@Model.ProductItems.Product.ProductComments.ToPagedList()" />
Essentially, calling ToPagedList()
at that point makes the code of the ProductDetail
method useless:
var items = _context.ProductComments
.Where(n => n.ProductId == sp.ProductItems.ProductId)
.OrderBy(c => c.CreateDate)
.ToPagedList(page ?? 1, 3);
...
return PartialView("_Comment", items);
As a result, the subset of data returned by ToPageList(page ?? 1, 3)
is never used and only the first page of comments is always shown.
To fix pagination pass the correct model returned by the ProductDetail
method to the partial view:
<partial name="_Comment" model="@Model" />
The above is based on your model declaration of the partial view:
@model X.PagedList.IPagedList<Laptop.Models.ProductComment>
It is important to note that the ProductDetail
method needs to provide both the product details page and the comments partial view with the correct view model. Looking at your code it is safe to assume that you want to pass the product to the first and the comments for that product to the latter. Here's an example to do that:
View model:
public class ProductVariationViewModel
{
public ProductVariation Product { get; set; }
public IEnumerable<ProductComment> Comments { get; set; }
}
Controller:
public async Task<IActionResult> ProductDetail(int? id, int? page)
{
var sp = await _context.ProductVariations...FirstOrDefaultAsync(...);
var items = _context.ProductComments.Where(...).ToPagedList(page ?? 1, 3);
var isAjax = Request.Headers["X-Requested-With"] == "XMLHttpRequest";
if (isAjax)
{
return PartialView("_Comment", items);
}
return View(new ProductVariationViewModel
{
Product = sp;
Comments = items;
});
}
Product detail page:
@model ProductVariationViewModel
<div id="table1">
<partial name="_Comment" model="@Model.Comments"/>
</div>
Comments partial view:
@using X.Web.PagedList
@using X.PagedList
@model IPagedList<ProductComment>
...
Other Fixes
There's also a nasty bug in your javascript code:
$("#table1").on("click", ".pagination a", function (event) {
You can see what's happening when you're using .on("click", ...)
for the event handler in the Network tab of the developer's tools in your browser:
Those are the ajax calls when I navigated to pages 2, 3 and 5. Note that the event handler is called multiple times instead of one for each page click. So, please use the code suggested in the answer you're following to fix that, too:
$("#table1 .pagination a").click(function(event) {
Last but not least, please make sure you're providing the correct arguments to the ProductDetail
method, which takes two parameters:
public async Task<IActionResult> ProductDetail(int? id, int? page)
In this case, the links generated by:
@Html.PagedListPager(Model, page => Url.Action("ProductDetail", "ProductView", new { page }))
will always make the id
parameter to be null
. You probably want to fix that by writing:
@Html.PagedListPager(Model, page => Url.Action("ProductDetail", "ProductView", new { id = ..., page = page }))
Hope that helps.