Reputation: 5446
We are following tutorial for Paging - https://learn.microsoft.com/en-us/aspnet/core/data/ef-rp/sort-filter-page?view=aspnetcore-2.1 and we are having an issue in relation to button Next and Previous for paging :
Severity Code Description Project File Line Suppression State Error CS1061 'IList' does not contain a definition for 'HasPreviousPage' and no accessible extension method 'HasPreviousPage' accepting a first argument of type 'IList' could be found (are you missing a using directive or an assembly reference?)
@{
var prevDisabled = !Model.TournamentAtheletes.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.TournamentAtheletes.HasNextPage ? "disabled" : "";
}
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.TournamentAtheletes.PageIndex - 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.TournamentAtheletes.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @nextDisabled">
Next
</a>
Any ideas?
I do have PaginatedList.cs class:
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int TotalPages { get; private set; }
public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
this.AddRange(items);
}
public bool HasPreviousPage
{
get
{
return (PageIndex > 1);
}
}
public bool HasNextPage
{
get
{
return (PageIndex < TotalPages);
}
}
public static async Task<PaginatedList<T>> CreateAsync(
IQueryable<T> source, int pageIndex, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip(
(pageIndex - 1) * pageSize)
.Take(pageSize).ToListAsync();
return new PaginatedList<T>(items, count, pageIndex, pageSize);
}
}
Here's my backend code for that index.cshtml:
public class IndexModel : PageModel
{
private readonly AthlosifyWebArchery.Data.ApplicationDbContext _context;
public IndexModel(AthlosifyWebArchery.Data.ApplicationDbContext context)
{
_context = context;
}
public string AtheleteNameSort { get; set; }
public string GenderSort { get; set; }
public string TotalRankingScoreSort { get; set; }
public string CurrentSort { get; set; }
public string CurrentFilter { get; set; }
public class TournamentAtheleteViewModel
{
public string AtheleteName { get; set; }
public string Gender { get; set; }
public string Contingent { get; set; }
public double TotalRankingScore { get; set; }
}
[BindProperty]
public IList<TournamentAtheleteViewModel> TournamentAtheletes { get;set; }
public async Task OnGetAsync(string sortOrder, string currentFilter, string searchString, int? pageIndex)
{
CurrentSort = sortOrder;
AtheleteNameSort = String.IsNullOrEmpty(sortOrder) ? "atheletename_desc" : "";
GenderSort = sortOrder == "gender" ? "gender_desc" : "gender";
TotalRankingScoreSort = sortOrder == "totalrankingscore" ? "totalrankingscore_desc" : "totalrankingscore";
if (searchString != null)
{
pageIndex = 1;
}
else
{
searchString = currentFilter;
}
CurrentFilter = searchString;
IQueryable<TournamentAtheleteViewModel> atheletes = _context.TournamentBatchItem
.GroupBy(t => new { t.AtheleteName, t.Gender, t.Contingent })
.Select(t => new TournamentAtheleteViewModel { AtheleteName = t.Key.AtheleteName,
Gender = t.Key.Gender,
Contingent = t.Key.Contingent,
TotalRankingScore = t.Sum(i => i.RankingScore) });
if (!String.IsNullOrEmpty(searchString))
{
atheletes = atheletes.Where(s => s.AtheleteName.Contains(searchString)
|| s.Contingent.Contains(searchString));
}
switch (sortOrder)
{
case "atheletename_desc":
atheletes = atheletes.OrderByDescending(s => s.AtheleteName);
break;
case "gender":
atheletes = atheletes.OrderBy(s => s.Gender);
break;
case "gender_desc":
atheletes = atheletes.OrderByDescending(s => s.Gender);
break;
case "totalrankingscore":
atheletes = atheletes.OrderByDescending(s => s.TotalRankingScore);
break;
case "totalrankingscore_desc":
atheletes = atheletes.OrderBy(s => s.TotalRankingScore);
break;
default:
atheletes = atheletes.OrderBy(s => s.AtheleteName);
break;
}
int pageSize = 3;
//TournamentAtheletes = await atheletes.AsNoTracking().ToListAsync();
TournamentAtheletes = await PaginatedList<TournamentAtheleteViewModel>.CreateAsync(
atheletes.AsNoTracking(), pageIndex ?? 1, pageSize);
}
}
Upvotes: 0
Views: 1060
Reputation: 38727
By declaring your list as this:
IList<TournamentAtheleteViewModel> TournamentAtheletes { get; set; }
You're explicitly stating that the only methods guaranteed to exist are those declared by the interface IList<T>
, which doesn't declare HasPreviousPage
or HasNextPage
.
The reason this happens is imagine I declare:
IList<TournamentAtheleteViewModel> TournamentAtheletes = new List<TournamentAtheleteViewModel>();
List<T>
certainly doesn't declare your methods, so this would cause a runtime exception if I called .HasPreviousPage
.
Because of this, you need to change this declaration to:
PaginatedList<TournamentAtheleteViewModel> TournamentAtheletes { get; set; }
Upvotes: 2