Paging not working when loadonce:true in jqGrid - asp.net-mvc

In jqGrid have property loadonce:true then i am getting only first page records. how can i get second and third page records.
code:
$(function () {
$("#pendingAppgrid").jqGrid({
colNames: ['Name', 'Email'],
colModel: [
{ name: 'Name', index: 'Name', sortable: true, align: 'left', width: '200',
editable: false, edittype: 'text',search:true
},
{ name: 'Email', index: 'Email', sortable: false, align: 'left', width: '200',
editable: false, edittype: 'text',search:true
},
],
pager: jQuery('#pager'),
sortname: 'Name',
rowNum: 15,
rowList: [10, 20, 25],
sortorder: "desc",
height: 345,
ignoreCase: true,
viewrecords: true,
rownumbers: true,
caption: 'Pending Approvals',
width: 660,
url: "#Url.Content("~/Home/PendingApprovals")",
datatype: 'json',
mtype: 'GET',
loadonce: true
})
jQuery("#pendingAppgrid").jqGrid('filterToolbar', { searchOnEnter: true, enableClear: false });
});
Server code
public ActionResult PendingApprovals(int page, int rows, string sidx, string sord)
{
//return View(GetPendingApprovals());
int currentPage = Convert.ToInt32(page) - 1;
int totalRecords = 0;
List<ViewModels.Channel.UserChannels> lTemChannel = new List<ViewModels.Channel.UserChannels>();
List<ViewModels.Channel.UserChannels> lstChannel = new List<ViewModels.Channel.UserChannels>();
lTemChannel = GetPendingApprovals();
foreach (ViewModels.Channel.UserChannels cha in lTemChannel)
{
ViewModels.Channel.UserChannels channelWithLogo = new ViewModels.Channel.UserChannels();
channelWithLogo.ID = cha.ID;
channelWithLogo.Name = cha.Name;
channelWithLogo.Email = cha.Email;
lstChannel.Add(channelWithLogo);
}
totalRecords = lstChannel.Count;
var totalPages = (int)Math.Ceiling(totalRecords / (float)rows);
lstChannel = lstChannel.ToList<ViewModels.Channel.UserChannels>();
IPagedList<ViewModels.Channel.UserChannels> ilstChannel;
switch (sord)
{
case "desc":
ilstChannel = lstChannel.OrderByDescending(m => m.Name).ToPagedList(page, rows);
break;
case "asc":
ilstChannel = lstChannel.OrderBy(m => m.Name).ToPagedList(page, rows);
break;
default:
ilstChannel = lstChannel.OrderBy(m => m.Name).ToPagedList(page, rows);
break;
}
var data = ilstChannel;
var jsonData = new
{
total = totalPages,
page,
records = totalRecords,
rows = (from m in data
select new
{
id = m.ChannelID,
cell = new object[]
{
m.Name,
m.Email
}
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
Here i am getting only first page records. i have more pages. search functionality working fine. problem is i am only first page records. not getting other pages records. how can i get another page records. Please help this.

If you use loadonce:true jqGrid change the datatype parameters to 'local' after the first load of data from the grid. All next grid reloading (sorting, paging, filtering) works local. If you want refresh the grid data from the server one more time you should set datatype to its original value ('json' or 'xml'). For example:
$("#pendingAppgrid").setGridParam({datatype:'json', page:1}).trigger('reloadGrid');
Please visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options for more details of the jqGrid options.

The problem is complex, read all even the comentaries, you need to recover the actual page of the Jgrid with:
var llPage = $("#listaCfdi").jqGrid('getGridParam', 'page');
//1 but this page is not the page of the "pager" and is before to call the method that fill the jgrid again
//, so the page will change after to fill the grid, you must call "onPaging" to fill again the Jgrid, like this:
//2
, onPaging: function (pgButton) {
FillAgainJgrid();
}
and in FillAgainJgrid(); (in this example) you need to call again other method that will have the real page of the "pager" that the user want, in example, the jgrid is in the page:5, and you want the las page, something like page:15, so the second call will have the real page, that the importan thing of the second call. Only it needs two calls to be sure that the page is the correct. And in this example, FillAgainJgridEnsure(); is exact to FillAgainJgrid(); except that doesnt have onPaging again
//3. In the server side, the page you are passed to the method only will work in the first call, because have all the data
//, and all the pages, but in example in the second call with the page:3, the jgrid will lost all the real information about the size of page, and only will return page:3 like if was the only one, you need a trick like this
//, (they are two list, one with all the data, and then you will get only the page you need, and the second list will have all the other rows in empty
//, so in this way you will get always all the correct rows number of the query, you need Concat in this example because we need all the rows, and if you are filled with dataset, in the sql server you need to use union all) :
ENTIDADES.Cfdi[] resultadoDos = null; //This is the class to provide the correct number of rows
//this is the query that always will have all the data
resultado = new CLASES.DAL.Facturacion().ObtenerCfdiDisponibles(criteriosBusqueda);
if (resultado.Length > 100)
{
resultadoDos = new ENTIDADES.Cfdi[resultado.Length - 100];
for (int i = 0; i < resultado.Length - 100; i++)
{
ENTIDADES.Cfdi referenciaVacia = new ENTIDADES.Cfdi();
resultadoDos[i] = referenciaVacia;
}
}
//Paging here, in the server size
resultado = resultado.OrderBy(p => p.Cliente).Skip(((Convert.ToInt32(_Pagina)) - 1) * 100).Take(100).ToArray();
if (resultadoDos != null) //if there are more that 100 rows, in this example
{//concat the page and the fill data empty
resultado = resultado.Concat(resultadoDos).OrderByDescending(x => x.Cliente).ToArray();
}
regresar = Newtonsoft.Json.JsonConvert.SerializeObject(resultado);
//Note, dont forget to OrderByDescending (in this example), because it will show first the data that have the rows filled, 100 is the size of rows of the page.
Omar Romero Mexico City

Related

In MVC 3, how do I refresh kendo grid in a partial view after I select a row in another partial view Kendo Grid?

I have a view with 3 partial views. The first partial view has a Kendo grid and when you select a row in the grid it populates and displays the 2nd partial view which has another kendo grid. It also populates and displays the 3rd partial view with another grid.
If I select a row in the 2nd kendo grid, i want it to insert data into the database table that the 3rd grid is using and I want it to refresh that 3rd grid with the new data.
I also have a custom button(retire) in the 3rd grid on each row that will also need to update that same grid by removing the item that was retired.
Can anyone help me set this up? Should I be using 3 partial views?
I guess you are using partial views to load each grid and it's data, that will work but you will have to refresh the entire page when a row is selected on the second grid in order to fill the third grid.
However Kendo Grid to a remote data source works well for this, you can then ignore loading the data into the grids within your partial views and use a bit of jQuery to ask the third grid to update on change event.
I find it much faster to fill grids with data via Ajax then when the page loads - but I have lots of data!
I have a grid updating for a person search which updates every time the search textbox changes
Grid defined as:-
$("#PersonSearch").kendoGrid({
columns: [
{ title: "Organisation", field: "cn", encoded: true },
{ title: "First name", field: "fn", encoded: true },
{ title: "Last name", field: "ln", encoded: true },
{ title: "Type", field: "pt", encoded: true },
{ title: "Date of birth", field: "db", encoded: true, format: "{0:dd/MM/yy}" },
{ title: "NHS number", field: "nn", encoded: true }
],
//sortable: { mode: "multiple" },
change: function () {
var selected = this.select()
data = this.dataSource.getByUid(selected.data("uid"));
if (data.url != "") {
.... do anything on a row being selected
}
else {
this.clearSelection();
}
},
filterable: false,
scrollable: { virtual: true },
sortable: true,
selectable: true,
groupable: false,
height: 480,
dataSource: {
transport: { read: { url: "../Person/PeopleRead/", type: "POST" } },
pageSize: 100,
serverPaging: true,
serverSorting: true,
sort: [
{ field: "cn", dir: "asc" },
{ field: "ln", dir: "asc" },
{ field: "fn", dir: "asc" },
],
serverFiltering: true,
serverGrouping: true,
serverAggregates: true,
type: "aspnetmvc-ajax",
filter: [],
schema: {
data: "Data", total: "Total", errors: "Errors",
model: {
id: "cID",
fields: {
db: { type: "date", defaultValue: null }
}
}
}
}
});
I trigger the Grid to fill with more data when the search box is changed :-
$('#GenericSearchString').keyup(function () {
// get a reference to the grid widget
var grid = $("#PersonSearch").data("kendoGrid");
// refreshes the grid
grid.refresh();
grid.dataSource.transport.options.read.url = "../Person/PeopleRead/" + $(this).val();
grid.dataSource.fetch();
});
On the server side in the Person controller I have a method PeopleRead :-
[HttpPost]
public ActionResult PeopleRead(String id, [DataSourceRequest]DataSourceRequest request)
{
WebCacheController Cache = ViewBag.Cache;
if (id == null) id = "";
string urlBase = Url.Content("~/");
var PeopleList = from c in db.Connections
where c.Person.Firstname.Contains(id) || c.Person.LastName.Contains(id)
select new
{
oID = c.Organisation.OrganisationID,
connID = c.ConnectionID,
cn = c.Organisation.Name,
fn = c.Person.Firstname,
pt =
(
c.Type == ModelEnums.ConnectionTypes.Customer ? "Customer" :
c.Type == ModelEnums.ConnectionTypes.Owner ? "Owner" :
c.Type == ModelEnums.ConnectionTypes.Service_User ? "Service user" :
c.Type == ModelEnums.ConnectionTypes.Worker ? "Worker" :
c.Type == ModelEnums.ConnectionTypes.Profile ? "Profile" : "Unknown"
),
url =
(
c.Type == ModelEnums.ConnectionTypes.Customer ? "" :
c.Type == ModelEnums.ConnectionTypes.Owner ? "" :
c.Type == ModelEnums.ConnectionTypes.Service_User ? urlBase + "ServiceUser/Details/" :
c.Type == ModelEnums.ConnectionTypes.Worker ? urlBase + "Worker/Details/" :
c.Type == ModelEnums.ConnectionTypes.Profile ? "" : ""
),
ln = c.Person.LastName,
nn = c.Person.NHSNumber,
db = c.Person.DateOfBirth
};
DataSourceResult result = PeopleList.ToDataSourceResult(request);
return Json(result);
}
Sorry the example is a bit off topic, but I though better to have working code as an example.
In your case the change: of the second grid would change the grid3.dataSource.transport.options.read.url and then do a grid3.dataSource.fetch();
I have to include the reference kendo.mvc along with many more on the mvc project as well as a link to kendo.aspnetmvc.min.js in the cshtml.

Server Side Paging in Kendo Grid?

I want client side grid paging in Kendo Grid. In grid only first 50 or 100 data will be shown in first page. And when customer click next page, other 50 or 100 data will be shown. I don't want to get all data from my server. because there will be million data in database and customer doesn't want to wait service to get all data from server. when he/she click next page, other data should request from server. How can I do it?
my controller
[HttpGet]
public JsonResult Getdata()
{
var reports = db.ActivityLog.OrderBy(c => c.dateTime).ToList();
var collection = reports.Select(x => new
{
username = x.uName,
location = x.locName,
devices = x.devName
});
return Json(collection, JsonRequestBehavior.AllowGet);
}
my view
function handleDataFromServer() {
$("#grid").data("kendoGrid").dataSource.read();
}
window.setInterval("handleDataFromServer()", 10000);
$(document).ready(function () {
$("#grid").kendoGrid({
sortable: true,
pageable: {
input: true,
numeric: false
},
selectable: "multiple",
dataSource: {
transport: {
read: "/Home/Getdata",
type: "json"
}
},
columns: [
{ field: "username", width: "80px" },
{ field: "location", width: "80px" },
{ field: "devices", width: "80px" }]
});
});
In Kendo you can do that easily. You just need to turn serverPaging: true. But as far as I can recall true is default. Anyway, need to declare it inside the dataSource as follows.
dataSource: {
transport: {},
pageSize: 50,
serverPaging: true,
},
pageable: {
refresh: true,
pageSizes: [25, 50, 100]
}
If serverPaging is true for every new page request Kendo will send a request to Server to fetch the next lot according to your server fetching logic. Let me know if this helps.
See also this github project KendoGridBinderEx which is also available as NuGet package.
Demo can be found here.
Follow this article which explains the serverside paging, sorting and other options with proper code and explanation.
http://blog.longle.net/2012/04/13/teleriks-html5-kendo-ui-grid-with-server-side-paging-sorting-filtering-with-mvc3-ef4-dynamic-linq/
hope this helps.

jqGrid navigation button fired post method?

jqGrid
$(document).ready(function () {
$("#grid").jqGrid({
url: '#Url.Action("GetAllAuthors", "Admin")',
datatype: "json",
mtype: 'get',
colNames: ['Yazar Adı', 'Öz Geçmiş'],
colModel: [
{ name: 'Name', index: 'Name', editable: false },
{ name: 'Description', index: 'Description', editable: false }
],
jsonReader: {
repeatitems: false,
id: "sno",
root: "rows", //array containing actual data
page: "page", //current page
total: "total", //total pages for the query
records: "records", //total number of records
repeatitems: false
},
rowNum: 10,
rowList: [10, 20, 30, 40, 50],
pager: jQuery('#gridpager'),
sortname: 'Name',
viewrecords: true,
sortorder: "asc",
width: 710,
height: 300
})
.navGrid('#gridpager', { edit: false, add: false, del: false, search: false, refresh: false })
.navButtonAdd('#gridpager', {
caption: "Düzenle",
buttonicon: "ui-icon-pencil",
onClickButton: function () {
var grid = $("#grid");
var rowid = grid.jqGrid('getGridParam', 'selrow');
//alert(rowid + " - " + grid.jqGrid('getCell', rowid, 'CustomerName') + " - Link: " + $("#customers_grid_table a.customer_details").attr("href"));
window.location = '#Url.Action("EditAuthor", "Admin")?authorId=' + rowid;
//LoadAction('#Url.Action("EditAuthor", "Admin")?authorId=' + rowid);
}
}); //end jqgrid
});
I have two method in my controller
Get method
[HttpGet]
public ActionResult EditAuthor(int authorId)
Post method
[HttpPost]
public ActionResult EditAuthor(AuthorViewModel model, HttpPostedFileBase file)
I selected a row and clicked edit button, I expect to fire get method, but post method is fired. What can I do to fire get method?
Thanks.
If you set new value of window.location the HTTP GET will be used. To produce HTTP POST you can either use $.ajax or submit some form. You can for example dynamically build invisible <form> and submit it. For example
onClickButton: function () {
var rowid = $(this).jqGrid("getGridParam", "selrow"),
myForm = document.createElement("form"),
param1 = document.createElement("input");
myForm.action = '#Url.Action("EditAuthor", "Admin")';
myForm.method = "POST";
myForm.style.display="none";
param1.name = "authorId";
param1.type = "text";
param1.value = rowid;
myForm.appendChild(param1);
document.body.appendChild(myForm);
myForm.submit();
document.body.removeChild(myForm);
}
I recommend you additionally to include additional validation whether some row is selected (whether rowid is not null).
Moreover I recommend you
to use always gridview: true option in the grid which will just improve the performance of the grid.
replace the option pager: jQuery('#gridpager') to pager: '#gridpager'.
replace the current value of jsonReader option to jsonReader: {repeatitems: false, id: "sno"}. The options which you specify will be combined with default value (see the documentation). Additionally your current value of jsonReader option contains syntax error because you specify the same property repeatitems: false twice.

jqGrid boolean or enumeration dropdown filtering for columns

I'm using jqGrid to display tabular data on my first ASP.NET MVC 3 and find it really useful, particularly filtering down data. For string-type I use the column-filtering with "contains" and that works wonderfully for culling out the strings. For the date data I use the date picker. Great.
Now I've got a few columns (e.g., "Contains nuts") which are essentially boolean values. I want to provide a way to filter these. Right now they are displayed as "true" and "false" and use the same string-based filtering that my string-type columns use. That's a bit clunky. I think what I'd like to do instead is have a way to choose one of three values (true/false/both) via a dropdown mechanism.
My current colModel has an entry like so for my 'boolean' field:
{ name: 'ContainsNuts',
index: 'ContainsNuts',
align: 'left',
searchoptions: { sopt: ['eq, 'ne']}
}
which only works when the user types in 'false' or 'true' - again, clunky.
For a few other columns, I wanted to use dropdowns for enumerations, e.g., I have a 'Cones' column, since there are quite a few rows and I page the results - using the auto complete text filtering is a bit hit-or-miss for the user to find all the possible values. Hope that makes sense.
So what I've tried is this - I created a controller action that looks like so:
public JsonResult AvailableCones()
{
var context = new IceCreamEntities();
var query = context.Cones.AsQueryable().Distinct();
List<string> all = query.Select(m => m.Name).ToList();
return Json(all, JsonRequestBehavior.AllowGet);
}
And I did something like this [perhaps convoluted approach] to create a dropdown selection in the filtering dialog for Cones in my document ready:
...
createSearchSelection = function (someValues) {
var outputValues = "";
if (someValues && someValues.length) {
for (var i = 0, j = someValues.length; i < j; ++i) {
var entry = someValues[i];
if (outputValues.length > 0) {
outputValues += ";";
}
outputValues += entry + ":" + entry;
}
}
return outputValues;
}
setTheSearchSelections = function (colName, url){
$('#icecreamgrid').jqGrid('setColProp', colName,
{
stype: 'select',
searchoptions: {
value: createSearchSelection(url),
sopt: ['eq']
}
});
}
gotData = function(data) {
setTheSearchSelections('ConeType', data);
}
var url = "/IceCream/AvailableConeTypes";
$.get(url, null, gotData);
The result is that I get a drop-down for the ConeType column in the search dialog and the correct rows shows up in the column. Great. That's pretty cool that it works.
What I don't know how to do, however, is to get a dropdown to show up in my column header filter just like the one that now shows up in the filter dialog. How can I augment what I have to make this happen? Secondly, how can I make what I've got work for boolean values?
First part of your question is the displaying and filtering of the boolean values. I use checkboxes to display such values. In difference on your case I have typically many such columns. To reduce the size of the JSON data I use "1" and "0" instead of "true" and "false". Next I use the following column settings
formatter: 'checkbox', align: 'center', width: 20,
edittype: 'checkbox', editoptions: { value: "1:0" },
stype: "select", searchoptions: { sopt: ['eq', 'ne'], value: "1:Yes;0:No"
So for the searching the user have to choose "Yes" or "No" in the select box. Because I have many of such columns I defined templateCeckbox object in one JavaScript file which I include on every page of the project:
my.templateCeckbox = {
formatter: 'checkbox', align: 'center', width: 20,
edittype: 'checkbox', editoptions: { value: "1:0" },
stype: "select", searchoptions: { sopt: ['eq', 'ne'], value: "1:Ja;0:Nein" }
};
Then the typical column definition is
{
name: 'IsInBasis', index: 'InBasis', template: my.templateCeckbox,
cellattr: function () { return ' title="TS-Basis"'; }
},
(see the answer for details about the column templates). I find also practical if the tooltip shown if one hover the checkbox will be the text close to the column header. So I use cellattr attribute. In case of having many columns with the checkboxes it improves the usability a little.
To be able to display many columns with chechboxes I use personally vertical column headers. I recommend you to read the old answer which could be additionally interesting because it describes how to implement quick filtering of the data with respect of external checkbox panel.
Now about the building of the selects for the 'Cones' column. If you has AvailableCones action which provide the list of possible options like array (list) of strings you should use dataUrl:'/IceCream/AvailableConeTypes' instead of value: createSearchSelection(url) as the searchoptions. You well add only the buildSelect function which I described in "UPDATED" part of the answer.
{
name: 'ConeType', width: 117, index: 'ConeType', editable: true, align: 'center',
edittype: 'select', stype: 'select',
editoptions: {
dataUrl: urlBase + '/AvailableConeTypes',
buildSelect: my.buildSelect
},
searchoptions: {
dataUrl: urlBase + '/AvailableConeTypes',
buildSelect: my.buildSelect
}
}
where
my.buildSelect = function(data) {
var response = jQuery.parseJSON(data.responseText),
s = '<select>', i, l, ri;
if (response && response.length) {
for (i=0, l=response.length; i<l; i += 1) {
ri = response[i];
s += '<option value="' + ri + '">' + ri + '</option>';
}
}
return s + '</select>';
};
This line of code shows a True,False dropdownlist for a column that has true, false values:
{
name: 'SReqdFlag', index: 'SReqdFlag', editable: true, edittype: 'select', editoptions: { value: '"":Select;true:True;false:False' }
}
Hope that helps!

How to implement search on jqgrid?

So I've got basic example of jqgrid working in ASP.NET MVC, the javascript looks like this:
$(document).ready(function() {
$("#list").jqGrid({
url: '../../Home/Example',
datatype: 'json',
myType: 'GET',
colNames: ['Id', 'Action', 'Parameters'],
colModel: [
{ name: 'id', index: 'id', width: 55, resizable: true },
{ name: 'action', index: 'action', width: 90, resizable: true },
{ name: 'paramters', index: 'parameters', width: 120, resizable: true}],
pager: $('#pager'),
rowNum: 10,
rowList: [10, 20, 30],
sortname: 'id',
sortorder: 'desc',
viewrecords: true,
multikey: "ctrlKey",
imgpath: '../../themes/basic/images',
caption: 'Messages'
});
Now I am trying to implement the search button that they have in the jqgrid examples (click on Manipulating/Grid Data). But I don't see how they implement it. I'm expecting e.g. a "search:true" and a method to implement it.
Has anyone implemented search on jqgrid or know of examples that show explicitly how to do it?
I recently implemented this myself (yesterday actually) for the first time. The biggest hurdle for me was figuring out how to write the controller function. The function signature is what took me the longest to figure out (notice the _search, searchField, searchOper, and searchString parameters as those are missing from most of asp.net mvc examples I've seen). The javascript posts to the controller for both the initial load and for the search call. You'll see in the code that I'm checking whether the _search parameter is true or not.
Below is the controller and the javascript code. My apologies for any formatting issues as this is my first time posting on here.
public ActionResult GetAppGroups(string sidx, string sord, int page, int rows, bool _search, string searchField, string searchOper, string searchString)
{
List<AppGroup> groups = service.GetAppGroups();
List<AppGroup> results;
if (_search)
results = groups.Where(x => x.Name.Contains(searchString)).ToList();
else
results = groups.Skip(page * rows).Take(rows).ToList();
int i = 1;
var jsonData = new
{
total = groups.Count / 20,
page = page,
records = groups.Count,
rows = (
from appgroup in results
select new
{
i = i++,
cell = new string[] {
appgroup.Name,
appgroup.Description
}
}).ToArray()
};
return Json(jsonData);
}
And here is my HTML/Javascript:
$(document).ready(function() {
$("#listGroups").jqGrid({
url: '<%= ResolveUrl("~/JSON/GetAppGroups/") %>',
datatype: 'json',
mtype: 'GET',
caption: 'App Groups',
colNames: ['Name', 'Description'],
colModel: [
{ name: 'Name', index: 'Name', width: 250, resizable: true, editable: false},
{ name: 'Description', index: 'Description', width: 650, resizable: true, editable: false},
],
loadtext: 'Loading Unix App Groups...',
multiselect: true,
pager: $("#pager"),
rowNum: 10,
rowList: [5,10,20,50],
sortname: 'ID',
sortorder: 'desc',
viewrecords: true,
imgpath: '../scripts/jqgrid/themes/basic/images'
//});
}).navGrid('#pager', {search:true, edit: false, add:false, del:false, searchtext:"Search"});
See my article on codeproject, which explains how we can do multiple search in jqgrid:
Using jqGrid’s search toolbar with multiple filters in ASP.NET MVC
I use IModelBinder for grid's settings binding, expression trees for sorting and filtering data.
In case you're still wondering about dealing with optional parameters, just declare them as nullables by adding a ? after the type name.
Now you'll be able to compare them with null to check if they are absent.
Note that you don't need to do this with strings, as they are already nullable.
#Alan - ok, I used your method and extended my webservice to expect those additional three parameters and check for "_search" is true/false. But, in order to make this work, I had to add this to my ajax call in the JavaScript:
if (!postdata._search) {
jQuery("#mygrid").appendPostData( {searchField:'', searchOper:'', searchString:''});
}
Just follow this link. It has all implementations explained...
You can create a button searchBtn and can invoke search form on click
$("#searchBtn").click(function(){
jQuery("#list4").searchGrid(
{options}
)});

Resources