ASP.NET MVC PagedList using AJAX in partial view

I am creating an ASP.NET MVC 5 application using Visual Studio 2015. The search is performed fine on the first try, but then if I click on any page number in the MVC PagedList component , it will generate Internal Server Error . Here is the form of AJAX; note that it passes the data received from the search to the partial view:

 @using (Ajax.BeginForm("SearchCustomers", "Permits", new AjaxOptions { UpdateTargetId = "targetElement", OnSuccess = "onAjaxSuccess", OnFailure = "onAjaxFailure" }, new { @class = "form-horizontal form-small", role = "form", id="customerSearchForm" })) { @Html.AntiForgeryToken() <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <h4>Customer Search</h4> </div> <div class="modal-body"> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group-sm clearfix"> @Html.LabelFor(m => m.SearchVm.SearchCustomerNameNumber, new { @class = "control-label col-xs-5 col-md-5" }) <div class="col-xs-5 col-md-5"> <div class="input-group"> @Html.EditorFor(m => m.SearchVm.SearchCustomerNameNumber, new {htmlAttributes = new {@class = "form-control"}}) <span class="input-group-btn"> <button type="submit" class="btn btn-custom-success btn-sm btn-custom-sm small-box-shadow btn-block"> Search <i class="fa fa-search fa-lg" aria-hidden="true"></i> </button> </span> </div> @Html.ValidationMessageFor(m => m.SearchVm.SearchCustomerNameNumber, "", new { @class = "text-danger" }) </div> </div> <div class="modal-search" id="targetElement"> @Html.Partial("_PermitsCustomerList", Model.SearchVm.Customers) </div> </div> } 

In a partial view of _PermitsCustomerList , I have the following:

 @using PagedList @using PagedList.Mvc @model IPagedList<MyProject.ViewModels.CustomerViewModel> @if (Model != null && Model.Count > 0) { <div class="panel panel-default data-grid data-grid-wide"> <table class="table table-hover table-striped table-bordered table-responsive"> <tr> <th> Customer # </th> <th> Customer Name </th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Customer_NO) </td> <td> @Html.DisplayFor(modelItem => item.Customer_Name) </td> </tr> } </table> <div id="contentPager"> @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", new { page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "targetElement", OnSuccess = "onAjaxSuccess", OnFailure = "onAjaxFailure" })) </div> </div> } 

And here is the action on the controller:

 [HttpPost] [ValidateAntiForgeryToken] public PartialViewResult SearchCustomers(PermitsViewModel permitsVm, int? page) { if (string.IsNullOrEmpty(permitsVm.SearchVm.SearchCustomerNameNumber)) return null; permitsVm.Page = page; int number; var list = int.TryParse(permitsVm.SearchVm.SearchCustomerNameNumber, out number) ? CustomerDataService.SearchCustomerByNumber(number) : CustomerDataService.SearchCustomerByName(permitsVm.SearchVm.SearchCustomerNameNumber); return PartialView("_PermitsCreateCustomerList", list.ToPagedList(permitsVm.Page ?? 1, 10)); } 

Here are the success and failure callback functions:

 function onAjaxFailure(xhr, status, error) { $("#targetElement").html("<strong>An error occurred retrieving data:" + error + "<br/>.</strong>"); } function onAjaxSuccess(data, status, xhr) { if (!$.trim(data)) { $("#targetElement").html("<div class='text-center'><strong>No results found for search.</strong></div>"); } } 

I looked at this example: MVC 4 Using Paged List in a partial view and added PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing , but something is still missing.

When I look at the console panel in Chrome, it has this error when I click on the page number:

http: // localhost: 9999 / MyProject / Permits / SearchCustomers? page = 2 500 (Internal server error)

What am I doing wrong when I try to make an AJAX call using the PagedList component?

+5
source share
2 answers

After many trial errors (mostly an error!), The answer was to not use the view model field for the search.

Here's the new search box in the main view:

 @{ string searchName = ViewBag.SearchName; } @Html.EditorFor(x => searchName, new {htmlAttributes = new {@class = "form-control"}}) 

Then in action this change gets the value of searchName :

 [HttpPost] [ValidateAntiForgeryToken] public PartialViewResult CreateSearch(string searchName, int? page) { if (string.IsNullOrEmpty(searchName)) return null; int number; var list = int.TryParse(searchName, out number) ? CustomerDataService.SearchCustomerByNumber(number) : CustomerDataService.SearchCustomerByName(searchName); var permitsVm = new PermitsViewModel {SearchVm = {Customers = list.ToPagedList(page ?? 1, 20)}}; ViewBag.SearchName = searchName; return PartialView("_PermitsCreateCustomerList", permitsVm); } 

Note the ViewBag.SearchName ; which will be used to pass the value of the search field to a partial view.

 <div id="contentPager"> @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", new { ViewBag.SearchName, page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "targetElement", OnSuccess = "onAjaxSuccess", OnFailure = "onAjaxFailure" })) </div> 

In the above paging mechanism, we use the ViewBag to pass the search value back to the controller.

Update 1: You will also need the following on the main view (the one that contains the partial) to ensure that the anti-fake token will be sent when you click the numbers in the page:

 $.ajaxPrefilter(function(options, originalOptions, jqXHR) { if (options.type.toUpperCase() === "POST") { // We need to add the verificationToken to all POSTs var token = $("input[name^=__RequestVerificationToken]").first(); if (!token.length) return; var tokenName = token.attr("name"); // If the data is JSON, then we need to put the token in the QueryString: if (options.contentType.indexOf('application/json') === 0) { // Add the token to the URL, because we can't add it to the JSON data: options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize(); } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) { // Append to the data string: options.data += (options.data ? "&" : "") + token.serialize(); } } }); 

From here: https://gist.github.com/scottrippey/3428114

Update 2: You can use the view model on the controller, but must go through RouteValueDictionary :

 <div id="contentPager"> @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", new RouteValueDictionary() { { "Page", page}, { "SearchVm.SearchCustomerNameNumber", Model.SearchVm.SearchCustomerNameNumber } }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "targetElement", OnSuccess = "onAjaxSuccess", OnFailure = "onAjaxFailure" })) </div> 

In doing so, you change the action:

 [HttpPost] [ValidateAntiForgeryToken] public PartialViewResult CreateSearch(PermitsViewModel permitsVm) { if (string.IsNullOrEmpty(permitsVm.SearchVm.SearchCustomerNameNumber)) return null; int number; var list = int.TryParse(permitsVm.SearchVm.SearchCustomerNameNumber, out number) ? CustomerDataService.SearchCustomerByNumber(number) : CustomerDataService.SearchCustomerByName(permitsVm.SearchVm.SearchCustomerNameNumber); permitsVm.SearchVm.Customers = list.ToPagedList(permitsVm.Page ?? 1, 10); return PartialView("_PermitsCreateCustomerList", permitsVm); } 

The complex help objects on RouteValueDictionary came from here: fooobar.com/questions/494245 / ...

+4
source

It looks like you are not passing the required argument to your controller. Change the PagedListPager to this:

 @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", new { page = page, permitsVm = Json.Encode(Model)}), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "targetElement", OnSuccess = "onAjaxSuccess", OnFailure = "onAjaxFailure" })) 
+1
source

Source: https://habr.com/ru/post/1265104/


All Articles