I want to add paging to my table in ASP.NET Core MVC.
Issue: how can I link TotalRecords, PageNo, & PageSize from controller to the view? In Razor page its simple to bind them, but I don't know how to do this in MVC.
TotalRecords = Query.AsQueryable().Count();
PageNo = p;
PageSize = s;
Controller:
// Display Data
public async Task<IActionResult> DisplayData(int p = 1, int s = 20)
{
try
{
IQueryable<MyModel> query = await _services.GetData();
// Add Paging
query = await AddPaging(p, s, query);
// Display Data
List<MyModel> myData = await query.AsNoTracking().ToListAsync();
return View(myData); // return view with data
}
catch
{
return View(); // return empty view
}
}
// add paging
private async Task<IQueryable<MyModel>> AddPaging(int p, int s, IQueryable<MyModel> Query)
{
TotalRecords = Query.AsQueryable().Count();
PageNo = p;
PageSize = s;
Query = Query.Skip((p - 1) * s).Take(s);
return Query;
} // end of paging
View:
#model List<MyModel>
<table>
....
</table>
<paging total-records="Model.TotalRecords"
page-no="Model.PageNo"
show-prev-next="false"
show-first-last="false">
</paging>
I suggest to solve this problem with OOP standards.
First make a class that will do pagination.
Example:
public class Paginate<T>
{
public Paginate(List<T> datas, int currentPage, int totalPage)
{
Datas = datas;
CurrentPage = currentPage;
TotalPage = totalPage;
}
public List<T> Datas { get; set; }
public int CurrentPage { get; set; }
public int TotalPage { get; set; }
public bool HasPrev
{
get
{
return CurrentPage > 1;
}
}
public bool HasNext
{
get
{
return CurrentPage < TotalPage;
}
}
}
Then send data to view by this class.
public async Task<IActionResult> Index(int page = 1, int take = 5)
{
var datas = await _context.Datas
.Skip((page - 1) * take)
.Take(take)
.AsNoTracking()
.ToListAsync();
int dataCount = await _context.Datas.CountAsync();
int initCount = (int)Math.Ceiling((decimal)count / take);
Paginate<Categories> result = new Paginate<Datas>(datas , page, initCount );
return View(result);
}
Last step is sending initial datas to controller from view.
First your view will take data from pagination class.
#model Paginate<List<MyModel>>
Then your pagination component will send data to controller:
<ul>
<li class="#(Model.HasPrev?"":"disabled")">
<a asp-action="Index" asp-route-page="#(Model.CurrentPage-1)">Previous</a>
</li>
#for (int i = 1; i <= Model.TotalPage; i++)
{
<li class="#(i==Model.CurrentPage ? "disabled":"")">
<a asp-action="Index" asp-route-page="#i">#i</a>
</li>
}
<li class="#(Model.HasNext?"":"disabled")">
<a asp-action="Index" asp-route-page="#(Model.CurrentPage+1)">Next</a>
</li>
</ul>
If you analize all code I think it will be useful. Or you can take the business logic and apply it to your DisplayData and AddPaging methods.
Related
I am trying to fixed pagination in my project. But I do not get the correct result. I want to make this result 123 ... 12
PS I study with book Adam Freeman Pro ASP.NET Core MVC 2.
Project in GitHub https://github.com/JasARGHUN/StoreProject-
Pagin model PagingInfo.cs:
public class PagingInfo
{ public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public int TotalPages =>
(int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); }
Descriptor class PageLinkTagHelper.cs
[HtmlTargetElement("div", Attributes = "page-model")]
public class PageLinkTagHelper : TagHelper
{
private IUrlHelperFactory urlHelperFactory;
public PageLinkTagHelper(IUrlHelperFactory helperFactory)
{
urlHelperFactory = helperFactory;
}
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public PagingInfo PageModel { get; set; }
public string PageAction { get; set; }
[HtmlAttributeName(DictionaryAttributePrefix = "page-url-")]
public Dictionary<string, object> PageUrlValues { get; set; } = new Dictionary<string, object>();
public bool PageClassesEnabled { get; set; } = false;
public string PageClass { get; set; }
public string PageClassNormal { get; set; }
public string PageClassSelected { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
TagBuilder result = new TagBuilder("div");
for (int i = 1; i <= PageModel.TotalPages; i++)
{
TagBuilder tag = new TagBuilder("a");
PageUrlValues["productPage"] = i;
tag.Attributes["href"] = urlHelper.Action(PageAction, PageUrlValues);
if (PageClassesEnabled)
{
tag.AddCssClass(PageClass);
tag.AddCssClass(i == PageModel.CurrentPage
? PageClassSelected : PageClassNormal);
}
tag.InnerHtml.Append(i.ToString());
result.InnerHtml.AppendHtml(tag);
}
output.Content.AppendHtml(result.InnerHtml);
}
}
Pagination view model ProductsListViewModel
public class ProductsListViewModel
{
public IEnumerable<Product> Products { get; set; }
public PagingInfo PagingInfo { get; set; }
public string CurrentCategory { get; set; }
}
Controller ProductController.cs
public class ProductController : Controller
{
private IProductRepository _repository;
public int PageSize = 4;
public ProductController(IProductRepository repository)
{
_repository = repository;
}
public ViewResult List(string category, int productPage = 1) =>
View(new ProductsListViewModel
{
Products = _repository.Products
.Where(p => category == null || p.Category == category)
.OrderBy(p => p.ProductID)
.Skip((productPage - 1) * PageSize)
.Take(PageSize),
PagingInfo = new PagingInfo
{
CurrentPage = productPage,
ItemsPerPage = PageSize,
TotalItems = category == null ?
_repository.Products.Count() :
_repository.Products.Where(e =>
e.Category == category).Count()
},
CurrentCategory = category
});}
View List.cshtml
#model ProductsListViewModel
#foreach (var p in Model.Products)
{
#await Html.PartialAsync("ProductSummary", p);
}
<div page-model="#Model.PagingInfo" page-action="List" page-classes-enabled="true"
page-class="btn" page-class-normal="btn-secondary"
page-class-selected="btn-primary" page-url-category="#Model.CurrentCategory"
class="btn-group pull-right m-1"></div>
Navigation menu Navigation.cshtml
#model IEnumerable<string>
<a class="btn btn-block btn-secondary border mb-1"
asp-action="List"
asp-controller="Product"
asp-route-category="">Home</a>
<div>
#foreach (string category in Model)
{
<a class="btn btn-sm btn-block border #(category == ViewBag.SelectedCategory ? "btn-info": "btn-light")"
asp-action="List"
asp-controller="Product"
asp-route-category="#category"
asp-route-productPage="1">#category</a>
}
</div>
I want to do something like this pagination
Ok, i tried and resolv my trouble, updated Controller, TagHelper class and View.
Maybe someone will come in handy.
Controller:
public async Task<IActionResult> List(string category, int page = 1)
{
IQueryable<Product> source = _repository.Products.Where(p => category == null || p.Category == category)
.OrderBy(p => p.ProductID);
var count = await source.CountAsync();
var items = await source.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync();
PagingInfo pagingInfo = new PagingInfo(count, page, pageSize);
ProductsListViewModel productsListView = new ProductsListViewModel
{
PagingInfo = pagingInfo,
Products = items
};
return View(productsListView);}
View:
<h3><page-link page-model="Model.PagingInfo" page-action="List"></page-link></h3>
TagHelper class:
public class PageLinkTagHelper : TagHelper
{
private IUrlHelperFactory urlHelperFactory;
public PageLinkTagHelper(IUrlHelperFactory helperFactory)
{
urlHelperFactory = helperFactory;
}
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public PagingInfo PageModel { get; set; }
public string PageAction { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
output.TagName = "div";
// набор ссылок будет представлять список ul
TagBuilder tag = new TagBuilder("ul");
tag.AddCssClass("pagination");
// формируем три ссылки - на текущую, предыдущую и следующую
TagBuilder currentItem = CreateTag(PageModel.PageNumber, urlHelper);
// создаем ссылку на предыдущую страницу, если она есть
if (PageModel.HasPreviousPage)
{
TagBuilder prevItem = CreateTag(PageModel.PageNumber - 1, urlHelper);
tag.InnerHtml.AppendHtml(prevItem);
}
tag.InnerHtml.AppendHtml(currentItem);
// создаем ссылку на следующую страницу, если она есть
if (PageModel.HasNextPage)
{
TagBuilder nextItem = CreateTag(PageModel.PageNumber + 1, urlHelper);
tag.InnerHtml.AppendHtml(nextItem);
}
output.Content.AppendHtml(tag);
}
TagBuilder CreateTag(int pageNumber, IUrlHelper urlHelper)
{
TagBuilder item = new TagBuilder("li");
TagBuilder link = new TagBuilder("a");
if (pageNumber == this.PageModel.PageNumber)
{
item.AddCssClass("active");
}
else
{
link.Attributes["href"] = urlHelper.Action(PageAction, new { page = pageNumber });
}
link.InnerHtml.Append(pageNumber.ToString());
item.InnerHtml.AppendHtml(link);
return item;
}
}
}
Change your for loop
for (PageModel.CurrentPage; i <= PageModel.CurrentPage + 2; i++)
That will give you 3 results based on the current page.
Then you can add a button the first and the last page on either end of the html.
There's probably a more elegant approach but that should work.
controller/
public IActionResult Index(int page=1)
{
ViewBag.Page = page;
ViewBag.TotalPage = (int)Math.Ceiling(_context.Books.Include(x => x.Author).Include(x => x.Genre).Count() / 2d);
var data = _context.Books.Include(x => x.Author).Include(x => x.Genre).Skip((page - 1) * 2).Take(2).ToList();
return View(data);
}
cshtml/
<div aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item #(page==1?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="1"><<</a></li>
<li class="page-item #(page==1?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="#(page-1)"><</a></li>
#if (page == 1)
{
for (int i = page; i <= page + 2; i++)
{
<li class="page-item #(page==i?"active":"")"><a class="page-link" asp-action="index" asp-route-page="#i">#i</a></li>
}
}
else if (page == totalPages)
{
for (int i = page - 2; i <= page; i++)
{
<li class="page-item #(page==i?"active":"")"><a class="page-link" asp-action="index" asp-route-page="#i">#i</a></li>
}
}
else
{
for (int i = page - 1; i <= page + 1; i++)
{
<li class="page-item #(page==i?"active":"")"><a class="page-link" asp-action="index" asp-route-page="#i">#i</a></li>
}
}
<li class="page-item #(page==totalPages?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="#(page+1)">></a></li>
<li class="page-item #(page==totalPages?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="#totalPages">>></a></li>
</ul>
</div>
I'm trying to show my data in pages using DbContext .
This is my Controller :
public async Task<IActionResult> Index(int? page)
{
int _page;
if (page.HasValue)
{
_page = page.Value;
}
else
_page = 1;
return View(await _context.Agent.Skip(_page-1).Take(10).ToListAsync());
And my layout page that contain the link :
<li><a asp-area="" asp-controller="Agents" asp-action="Index" asp-route-id="1" >סוכן</a></li>
Two things:
A) It doesn't seems to work, no matter what I pass in asp-route-id the same list is beeing shown . What am I doing wrong ?
B) After it will work, how do I present the pages for the user to choose ? (E.G. 1,2,3..90)
Thanks.
Your parameter is named page but you provide an id route value. Rename the page parameter in action method to id and it should work.
Michal answered you first question. Concerning you second question you could use third-party tag helpers like pioneer-pagination
Or write you own implementation of pagination logic for view like below(mostly based on official documentation), not perfect one implementation of pagination, but still working:
Model for page:
public class PageViewModel
{
public int PageNumber { get; }
public int TotalPages { get; }
public PageViewModel(int count, int pageNumber, int pageSize)
{
PageNumber = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
}
public bool HasPreviousPage => (PageNumber > 1);
public bool HasNextPage => (PageNumber < TotalPages);
}
Code for tag helper:
public class PagerTagHelper : TagHelper
{
private IUrlHelperFactory urlHelperFactory;
public PagerTagHelper(IUrlHelperFactory helperFactory)
{
urlHelperFactory = helperFactory;
}
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public PageViewModel PageModel { get; set; }
public string PageAction { get; set; }
public string PageController { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
output.TagName = "div";
// we put our links in list
TagBuilder tag = new TagBuilder("ul");
tag.AddCssClass("pagination");
//show link for 1st page
if (PageModel.PageNumber>2)
{
TagBuilder fstItem = CreateTag(1, urlHelper);
tag.InnerHtml.AppendHtml(fstItem);
}
// create 3 links to current, next and previous page.
TagBuilder currentItem = CreateTag(PageModel.PageNumber, urlHelper);
// link to previous page if NOT 1st page
if (PageModel.HasPreviousPage)
{
TagBuilder prevItem = CreateTag(PageModel.PageNumber - 1, urlHelper);
tag.InnerHtml.AppendHtml(prevItem);
}
tag.InnerHtml.AppendHtml(currentItem);
// link to next page, if NOT last page
if (PageModel.HasNextPage)
{
TagBuilder nextItem = CreateTag(PageModel.PageNumber + 1, urlHelper);
tag.InnerHtml.AppendHtml(nextItem);
}
//show code for last page
if (PageModel.TotalPages > 4 && PageModel.PageNumber!=PageModel.TotalPages-1 && PageModel.HasNextPage)
{
TagBuilder lstItem = CreateTag(PageModel.TotalPages, urlHelper);
tag.InnerHtml.AppendHtml(lstItem);
}
output.Content.AppendHtml(tag);
}
TagBuilder CreateTag(int pageNumber, IUrlHelper urlHelper)
{
TagBuilder item = new TagBuilder("li");
TagBuilder link = new TagBuilder("a");
if (pageNumber == this.PageModel.PageNumber)
{
item.AddCssClass("active");
}
else
{
link.Attributes["href"] = urlHelper.Action(PageAction, PageController, new { page = pageNumber });
}
link.InnerHtml.Append(pageNumber.ToString());
item.InnerHtml.AppendHtml(link);
return item;
}
}
And use it in View like (don't forget to import tag-helper in _ViewImports.cshtml):
<pager page-model="#Model.PageViewModel" page-action="Index" page-controller="Home"></pager>
And code for controller:
public async Task<IActionResult> Index(int page=1)
{
int pageSize = 10;
var count = await _context.Agent.CountAsync();
var items = await _context.Agent.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync();
PageViewModel pageVm= new PageViewModel(count, page, pageSize);
IndexViewModel vm= new IndexViewModel
{
PageViewModel = pageVm,
Agents =items // need to create table in view from Agent properties
};
return View(vm);
}
And code for the IndexViewModel:
public class IndexViewModel
{
public IEnumerable<Agent> Agents { get; set; }
public PageViewModel PageViewModel { get; set; }
}
Update:
If you want display all PageLinks in your view you can just use for loop in Tag Helper Process method like below:
public override void Process(TagHelperContext context, TagHelperOutput output)
{
IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
output.TagName = "div";
// we put our links in list
TagBuilder tag = new TagBuilder("ul");
tag.AddCssClass("pagination");
for (int i = 1; i <= PageModel.TotalPages; i++)
{
TagBuilder linkItem = CreateTag(i, urlHelper);
tag.InnerHtml.AppendHtml(linkItem);
}
output.Content.AppendHtml(tag);
}
Update 2:
In order to use this approach don't forget to change the model for your index page to IndexViewModel and register tag helper in _ViewImports.cshtml. My working view (simplified) looks like this.
#* Using and tag helper imported in _ViewImports.cshtml *#
#model IndexViewModel
#{
ViewData["Title"] = "Home";
}
<div>
<table class="table">
<tr><th>Name</th><th>Age</th></tr>
#foreach (var a in Model.Agents)
{
<tr><td>#a.Name</td><td>#a.Age</td></tr>
}
</table>
</div>
<pager page-model="#Model.PageViewModel" page-action="Index" page-controller="Home"></pager>
Update 3:
If you use IndexViewModel like I wrote above, but don't use foreach like in my example, you should change #Html.DisplayNameFor(model => model.Name) to #Html.DisplayNameFor(model => model.Agents.Name)
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers imports only built-in ASP.NET Core tag helpers. In order to import custom tags you should use #addTagHelper *, YourAssemblyName where YourAssemblyName is the name of you project ('AgentApp` for example), see A minimal Tag Helper section in documentation for more info.
I am trying to pass a model to the controller using an ajax post, but every time I do so, the model is null and I lose all the data I am trying to persist.
The ajax call:
$('#next').click(function (e) {
e.preventDefault();
var url = '#Url.Action("Manage")'
var _model = JSON.stringify(#Html.Raw(Json.Encode(Model)));
var _page = #(Model.pager.CurrentPage + 1);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: url,
data: JSON.stringify({ 'model': _model, 'page': _page }),
success: function(result) {
console.log(result);
}
});
});
When I look at the serialized object, it looks like a correctly formatted JSON object with no errors thrown in the developer console.
The link that is triggering this jQuery call is just a basic action link:
#Html.ActionLink(">", "Manage", "Announcements", null, new { id = "next" })
My model is a little more complicated...
public class ManageViewModel : IEnumerable<EditViewModel>
{
[Display(Name="Start Date")]
[DataType(DataType.DateTime)]
public DateTime? StartDate { get; set; }
[Display(Name="End Date")]
[DataType(DataType.DateTime)]
public DateTime? EndDate { get; set; }
public string SearchString { get; set; }
public Pager pager { get; set; }
public List<EditViewModel> Data { get; set; }
public List<CategoryViewModel> Categories { get; set; }
public ManageViewModel()
{
Data = new List<EditViewModel>();
Categories = new List<CategoryViewModel>();
}
public IEnumerator<EditViewModel> GetEnumerator()
{
return Data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return Data.GetEnumerator();
}
}
public class Pager
{
public int TotalItems { get; private set; }
public int CurrentPage { get; private set; }
public int PageSize { get; private set; }
public int TotalPages { get; private set; }
public int StartPage { get; private set; }
public int EndPage { get; private set; }
public Pager(int totalItems, int? page, int pageSize = 10)
{
int totalPages = (int)Math.Ceiling((decimal)totalItems / (decimal)pageSize);
int currentPage = page ?? 1;
int startPage = currentPage - 5;
int endPage = currentPage + 4;
if(startPage <= 0)
{
endPage -= (startPage - 1);
startPage = 1;
}
if(endPage > totalPages)
{
endPage = totalPages;
if(endPage > 10)
{
startPage = endPage - 9;
}
}
TotalItems = totalItems;
TotalPages = totalPages;
CurrentPage = currentPage;
PageSize = pageSize;
EndPage = endPage;
StartPage = startPage;
}
}
I can't convert the links in to a form because that breaks the pagination. Or maybe I'm just not understanding the full picture here.
Here is the section of the View where the pagination is occurring
if (Model.pager.EndPage > 1)
{
<div style="color:#337AB7; padding-bottom: 0px;">Page #Model.pager.CurrentPage of #Model.pager.TotalPages</div>
<ul class="pagination">
#if (Model.pager.CurrentPage > 1)
{
<li>
#Html.ActionLink("<<", "Manage", new { model = Model, start = Model.StartDate, end = Model.EndDate, query = Model.SearchString }, null)
</li>
<li>
#Html.ActionLink("<", "Manage", new { model = Model, page = Model.pager.CurrentPage - 1, start = Model.StartDate, end = Model.EndDate, query = Model.SearchString }, null)
</li>
}
#for (var _page = Model.pager.StartPage; _page < Model.pager.EndPage + 1; _page++)
{
<li class="#(_page == Model.pager.CurrentPage ? "active" : "")">
#Html.ActionLink(_page.ToString(), "Manage", new { model = Model, page = _page, start = Model.StartDate, end = Model.EndDate, query = Model.SearchString }, null)
</li>
}
#if (Model.pager.CurrentPage < Model.pager.TotalPages)
{
<li>
#Html.ActionLink(">", "Manage", "Announcements", null, new { id = "next" })
</li>
<li>
#Html.ActionLink(">>", "Manage", new { model = Model, page = Model.pager.TotalPages, start = Model.StartDate, end = Model.EndDate, query = Model.SearchString }, null)
</li>
}
</ul>
}
The action links attempting to pass the model, obviously don't work but I left them because I am focusing on getting one to work, the one listed previously, before getting all the others configured.
I have looked at the following SO posts and have had no luck with them:
Post an MVC model with AJAX?
Model properties null on Ajax post from list box change event
How to send a model in jQuery $.ajax() post request to MVC controller method
Pass Model To Controller using Jquery/Ajax
How to pass model in ajax post request?
Any ideas on how I might be able to do this? I need the model data to persist for searching/filtering which is done through a form. Thank you in advance for taking a look and giving your insights!
You need to include a parameterless constructor for your models. From the screenshot you have sent it seems there isn't a parameterless constructor for public Pager model.
I'm using an example from Code Project: ASP.NET MVC-4,Entity Framework and JQGrid Demo with simple Todo List WebApplication. However, the developer didn't maximize cohesion since the the controller is doing all the business logic. I'm trying to decouple the JsonResult method, from the controller, and create loosely coupled classes that handle all the business logic from the model.
Here is my original code:
[HttpPost]
public JsonResult getPriceTable(string sidx, string sord, int page, int rows)
{
int pageIndex = Convert.ToInt32(page) - 1;
int pageSize = rows;
var modelPrices = db.VW_MODELS_CHARGEs
.OrderBy(x => x.SERIAL_CODE)
.Where(x => x.ACTIVE == 1)
.Select(x => new { x.VW_MC_OBJID, x.S_MODEL, x.CHARGE, x.SERIAL_CODE });
int totalRecords = modelPrices.Count();
var totalPages = (int)Math.Ceiling((float)totalRecords / (float)rows);
var jsonData = new
{
total = totalPages,
page,
records = totalRecords,
rows = modelPrices
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
to begin breaking up the logic, in the controller, I created several classes:
public class jqGridTable
{
public int pageIndex { get; set; }
public int pageSize { get; set; }
public int totalRecords { get; set; }
public int totalPages { get; set; }
public List<adminPriceTable> modelPricesList = new List<adminPriceTable>();
}
public class adminPriceTable
{
public int VW_MC_OBJID { get; set; }
public string S_MODEL { get; set; }
public string SERIAL_CODE { get; set; }
public decimal? CHARGE { get; set; }
}
and then the class below invokes the method to return the data:
public class adminPriceTableList
{
public static jqGridTable priceTableResult(string sidx, string sord, int page, int rows)
{
var jqGrid = new jqGridTable();
jqGrid.pageIndex = Convert.ToInt32(page) - 1;
jqGrid.pageSize = rows;
jqGrid.modelPricesList = NREContext.dbConn.VW_MODELS_CHARGEs
.OrderBy(x => x.SERIAL_CODE)
.Where(x => x.ACTIVE == 1)
.Select(x => new adminPriceTable
{
VW_MC_OBJID = x.VW_MC_OBJID,
SERIAL_CODE = x.SERIAL_CODE,
S_MODEL = x.S_MODEL,
CHARGE = x.CHARGE
}).ToList();
jqGrid.totalRecords = jqGrid.modelPricesList.Count();
jqGrid.totalPages = (int)Math.Ceiling((float)jqGrid.totalRecords / (float)rows);
return jqGrid;
}
}
so now, in the controller, I should be able to have the controller just invoke:
[HttpPost]
public JsonResult getPriceTable(string sidx, string sord, int page, int rows)
{
return Json(adminPriceTableList.priceTableResult(sidx, sord,page,rows), JsonRequestBehavior.AllowGet);
}
However, the jqGrid is not getting populated. I suspect it has something to do with (shown below) from the original code when the controller was handling all the logic.
var jsonData = new
{
total = totalPages,
page,
records = totalRecords,
rows = modelPrices
};
Can someone help me understand what I didn't do correctly? Do you see where I went wrong or where I'm not invoking the proper methods?
Thanks.
After reviewing the code, I failed to notice that modelPriceList:
public List<adminPriceTable> modelPricesList = new List<adminPriceTable>
needs to be the same name as modelPrices
var jsonData = new
{
total = totalPages,
page,
records = totalRecords,
rows = modelPrices
};
so after renaming the list....
public List<adminPriceTable> modelPrices = new List<adminPriceTable>
...produces results.
I have a page that is a list of users. The controller's Index function is the action responsible for showing the page of users. The user can select those users and chose to delete them.
I perform the delete action with an ajax request, however then the page's list of users is out of date. So I reload the page because I want to re-use the index action, and all the query string parameters are still there. This means I'm performing two round trips. How do I avoid this?
function DeleteUsers()
{
var selectedUserIds = ;
$.post("/Account/DeleteUsers",
{
userIds: selectedUserIds
},
function (data) {
if( data.status == "success"){
location.reload();
}
});
}
Index function:
[AuthorizeActionFilter]
public ActionResult Index(UserModel model)
{
ViewData["PageTitle"] = ServiceSite.Resources.Resources.REGISTERED_USERS;
ViewBag.MaxUsersPerPage = PAGE_MAX_COUNT;
if(model == null)
{
model = new UserModel();
}
int totalCount = 0;
//Get users
model.Users = CADC.GetUsers(AccountController.GetRegionID(), model.CompanyID, out totalCount,
model.SortField, model.PageNumber * PAGE_MAX_COUNT, PAGE_MAX_COUNT, model.Ascending, User.Identity.Name);
model.TotalUserCount = totalCount;
int totalPages = totalCount / PAGE_MAX_COUNT;
model.TotalPages = (totalCount % PAGE_MAX_COUNT) == 0 ? totalPages : totalPages + 1;
return View(model);
}
and the model:
public class UserModel
{
public bool Ascending { get; set; }
public int PageNumber { get; set; }
public string SortField { get; set; }
public int TotalUserCount { get; set; }
public int TotalPages { get; set; }
public long CompanyID { get; set; }
public List<User> Users { get; set; }
public UserModel()
{
this.Ascending = true;
this.PageNumber = 0;
this.SortField = "FirstName";
this.CompanyID = 0;
this.TotalUserCount = 0;
this.TotalPages = 0;
}
}
I agree with #David's comments. In the AJAX success block, remove the rows just deleted based on what you requested to delete.
The pagination is indeed more complicated; either adjust it in the same way, or revamp everything to use a proper view model in Javascript with bound elements--see AngularJS or other such frameworks.