Why jqGrid is very slow when number of rows displayed increases? - jqgrid
When I display a small amount per page, it's quick and very good. When I increase it to 100 or more it starts getting slow. At 1000 it's unbearable! This is the code used for drawing the grid:
$("#stSearchTermsGrid").jqGrid({
mtype: "POST",
postData:{},
datatype: function(postdata) {
$.ajax({
url: 'ajax/ajax_termsSearchGridSimple.php',
data: postdata,
async: false,
dataType: "xml",
error: function(){
alert('Error loading XML document');
},
success: function(data,stat,xmldata){
//check error
var $error=$(data).find('error').text();
if($error!="0")
{
messageBox("Error",$error);
return;
}
//content
var $content=$(data).find('content').text();
if($content!="0")
{
var thegrid = $("#stSearchTermsGrid")[0];
thegrid.addXmlData(xmldata.responseXML);
}
}
});
},
colNames:["tId","term", "revTerm", "uType","freq","description","fId","facet","modifiedTime"],
colModel:[
//tId
{name:'tId',index:'tId',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','in','ni']}},
//term (editable)
{name:'term',index:'term',searchoptions:{sopt:['eq','ne','in','ni','bw','bn','ew','en','cn','nc']},editable:true,edittype:'text',editoptions:{size:20},editrules:{required:true},formoptions:{elmsuffix:'(*)'}},
//revTerm (editable)
{name:'revTerm',index:'revTerm',searchoptions:{sopt:['eq','ne','in','ni','bw','bn','ew','en','cn','nc']},editable:true,edittype:'text',editoptions:{size:20},editrules:{required:true},formoptions:{elmsuffix:'(*)'}},
//uType (editable)
{name:'uType',index:'uType',align:"center",searchoptions:{sopt:['eq','ne','in','ni']},editable:true,edittype:'select',editoptions:{value:{'':'any','NPU':'proper noun','NU':'noun','VU':'verb'}}},
//freq
{name:'freq',index:'freq',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','in','ni']}},
//description (editable)
{name:'description',index:'description',searchoptions:{sopt:['bw','bn','ew','en','cn','nc']},editable:true,edittype:'textarea',editoptions:{rows:"3"}},
//fId
{name:'fId',index:'fId',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','in','ni']}},
//facet
{name:'facet',index:'facet',searchoptions:{sopt:['eq','ne','in','ni','bw','bn','ew','en','cn','nc']}},
//modifiedTime
{name:'modifiedTime',index:'modifiedTime',align:"center",searchoptions:{sopt:['eq','ne','lt','le','gt','ge','bw','bn','ew','en','cn','nc']}}
],
gridComplete: function(){
var $ids=$("#stSearchTermsGrid").jqGrid('getDataIDs');
for($i=0;$i<$ids.length;$i++){
var $reference="G";
//update columns
$("#stSearchTermsGrid").jqGrid('setRowData',$ids[$i],{"reference":$reference});
//coloring the recently classified row
var $colorRecentlyModified = '#DFFC91';
var modifiedTime = $("#stSearchTermsGrid").jqGrid('getCell',$ids[$i],'modifiedTime');
var timeDiff = Math.abs(new Date() - new Date(modifiedTime.replace(/-/g,'/')));
// 86400000 is the number of milliseconds in one day. Multiplying by days to mark the ones which are modified a few days ago
timeLimit = 86400000 * 1.5;
if(timeDiff < timeLimit)
{
for(colN=2; colN<9; colN++)
$("#stSearchTermsGrid").jqGrid('setCell', $ids[$i], colN, '', {'backgroundColor':$colorRecentlyModified});
}
//coloring the unclassified row
var $colorUnclassified = '#FFCECE';
var $fId = $("#stSearchTermsGrid").jqGrid('getCell',$ids[$i],'fId');
if($fId == "0")
{
for(colN=2; colN<9; colN++)
$("#stSearchTermsGrid").jqGrid('setCell', $ids[$i], colN, '', {'backgroundColor':$colorUnclassified});
}
}
},
sortable: true,
//autowidth:true,
width: 900, //width for grid
height: 250, //height for grid
sortname: 'term', //default sort column
caption: "Terms", //caption for grid (empty will hide)
hidegrid: false,
gridview: true, //load the grid more fast
multiselect: true, //support mulitselect
//multiboxonly: true,
pager: '#stSearchTermsGridPager',
rowNum:10,
rowList:[10,25,50,100,500,1000],
viewrecords: true, //show view record information
viewsortcols: [true,'vertical',true], //show sortable column with icons
editurl: 'ajax/ajax_termsEdit.php'
});
$("#stSearchTermsGrid").jqGrid('navGrid','#stSearchTermsGridPager',
{edit:true,add:false,del:true,search:true,view:true,refresh:true},
// edit options
{
onclickSubmit : function(params, posdata) {
var $tId=$("#stSearchTermsGrid").jqGrid('getGridParam','selrow');
if($tId && $tId.length>0)
{
var $rowAry=$("#stSearchTermsGrid").jqGrid('getRowData',$tId);
var $fId=$rowAry["fId"];
return {"fId":$fId}
}
},
afterSubmit : gridAfterSubmit,
reloadAfterSubmit: true,
closeOnEscape:true,
bottominfo:"Fields marked with (*) are required."
},
// add options
{},
//del options
{
msg: "Selected records(s) will be permanently deleted and cannot be recovered.<br/> Are you sure?",
afterSubmit : gridAfterSubmit,
reloadAfterSubmit: true,
closeOnEscape:true
},
// search options
{multipleSearch:true,closeOnEscape:true},
//view options
{
closeOnEscape:true
}
);
$("#stSearchTermsGrid").jqGrid('gridResize',{minWidth:900,maxWidth:2000,minHeight:250, maxHeight:1000});
I see many places where the grid can be improved.
1) You should use paging. If you show the user 1000 rows of data, the data will be not displayed on the monitor at once. The user have to scroll the windows of web browser to see the most parts of data. Which sense has to spend time to paint the parts of window which will not be seen? The scrolling of data with respect of jqGrid is much more effective as scrolling of browser window. Moreover no person are able to analyse the 1000 rows of data. He have to change sorting and set different filters to understand which from the data are interesting for him. It is one more argument for the data paging and implemented some searching. It you already use advanced searching you can consider to use additionally toolbar searching with the parameter stringResult:true which is compatible with the advanced searching.
2) you should rewrite the code of gridComplete totally. I suppose, that for relatively large number of rows the function is the bottleneck of your code. To verify this just temporary comment the function and compare the time of the grid painting. You should understand that every time you get data by id or set data by id jQuery will have to search the DOM element by id. Especially modification of data on the page can be very slow. By the way it seems to me that you set the same 'background-color' (what is 'backgroundColor' ???) CSS style for almost the whole cells of the rows. Why not set the 'background-color' for the row (<tr> element) instead?
3) I strictly recommend you not use datatype as function. Your server part should return some error HTTP code. In the case the loadError event will work and you can decode and display the custom error message. All other in your data seems be standard and you need not use datatype as function. If you will use datatype:"xml" you can for example try to use loadonce:true and implement client-side data paging and sorting if you will have problem with implementation of this features on the server.
I don't want to write too long text so I stop on the 3 most important points. By the way if you will switch from XML to JSON as the datatype used for the communication with the server, it will also improve a little the performance.
UPDATED: To see the performance of jqGrid with 1000 rows of data without paging and with data paging look at the links. Is by the way the performance of my example with 1000 rows without paging also so slow as in your case?
Related
jqgrid formatting based on certain value. spring jqgrid
I am new to the JQGRID, I need to format jqgrid based on certain values, lets say if the "NAME" column contains value of "HEMA" and "RAJU" then their respective row should contain the value of n/a (meaning their gender, mobile, location , country should be n/a). I am stuck as I could not figure out how to approach this problem in jqgrid. Guidance will be highly appreciated. I have attached image for clear explanation. I did some searching but could not find anything closest I could find was formatter but did not work. var url = "test/gridresult"; $(function(){ ("#result").jqGrid({ url:url, datatype: "jsonstring", multiselect:false, colNames:['Id','NAME', 'GENDER', 'MOBILE','LOCATION','COUNTRY'], colModel:[ {name:'id',index:'id', resizable:true}, {name:'name',index:'name', resizable:true}, {name:'mobile',index:'mobile', resizable:true}, {name:'country',index:'country', resizable:true}, ], rowNum:100, pager: '#prowed1', sortname: 'id', loadonce: true, sortorder: "desc", jsonReader;{ repeatitem:false, root:"rows", page:"page", records:"records", cell:"" } }); }); this seems working, I am getting name from loop but how do I set n/a in a row for that particular name var rows = $("#result").jqGrid('getDataIDs'); for (var i = 0; i < rows.length; i++) { var status = $("#resultTable2").getCell(rows[i],"NAME"); alert("initial value "+status); if(status == "HEMA") { //need to set value of n/a for row that belongs to HEMA } } <!-- begin snippet: js hide: false console: true babel: false --> demo pic for my question
Guys I was able to fix it using formatter. Spent good amount of time and finally got it fixed. function valFormat( cellvalue, options, rowObject ){ var val; if(rowObject.name=='HEMA' ){ val='N/A'; }else{ val=cellvalue; } return val; } and in the jqgrid: {name:'name',index:'name', resizable:true, formatter:valFormat},
ExtJS: 2 ajax store, 1 with an extra row
I have this code: Ext.define('storeBusiness',{ extend: 'Ext.data.Store', autoLoad: true, autoSync: true, model: 'Business', proxy: { type: 'ajax', api: { read: '../crud/ler_filter.php?db='+database+'&tbl=mercados', create: '../crud/criar.php?db='+database+'&tbl=mercados', update: '../crud/update.php?db='+database+'&tbl=mercados', destroy: '../crud/apagar.php?db='+database+'&tbl=mercados' }, reader: { type: 'json', root: 'rows' }, writer: { type:'json' } } }); var storeBusinessCombo = Ext.create('storeBusiness'); var storeBusiness = Ext.create('storeBusiness'); storeBusiness.add({id: 0, business: "All"}); I have 2 grids. One has storeBusiness and the other has storeProducts. The way the work is when I click on the business grid it filters the produts grid so that it shows the products of that business. On the business grid it has the storeBusiness that it fetches the records from a database. I want to fetch all business from the database and add one more record (named 'All') without writing it to the database. I dont want to add 'All' to the database because in the Product's grid I want to have a combobox that has all the business (storeBusinessCombo) without the 'All' record. Does anyone has any idea how I can do this? (the code above isn't doing what I want, storeBusiness shows all business without the 'All' in the grid) Important: This works if the Ext.define('storeBusiness', has a proxy that is of type: 'memory'
Two approaches come to mind: Add the "all" record to the store after load and don't sync so the record isn't sent to the server. Use memory proxy, retrieve the businesses records via Ajax request and assign them to the store via its data config.
To resolve this I have done: Put the Ext.define('storeBusiness',{ to autoLoad: false, Put this code: var storeBusinessCombo = Ext.create('storeBusiness', {autoLoad: true}); var storeBusiness = Ext.create('storeBusiness'); storeBusiness.on('beforeload', function(){ storeBusiness.loadData([{id: 0, business: "All"}]); } And you should put storeBusiness.load({addRecords: true}); when you want to load storeBusiness.
Grid not working after reloading on alternate calls
$("#tableVisualization").jqGrid('GridUnload'); $("#tableVisualization").jqGrid({ datatype: "local", mtype: 'GET', colNames: this.GetGridColumnNames(), colModel: this.GetGridColumnModel(), height: "100%", autowidth: true, shrinkToFit: true, sortname: 'monthID', sortorder: "desc", rowList: [6, 12], rowNum: 12, pager: $('#pager3'), viewrecords: true, recordpos: "left", caption: "Table" }); //local data array used for example var data = this.GetGridData(); //FUNCTION CALL //populate grid with data $("#tableVisualization").jqGrid("addRowData", "month", data); $("#tableVisualization").trigger("reloadGrid"); $("#tableVisualization").setGridWidth(1040, true); Above code works fine. However if I assign $("#tableVisualization") to a variable and use the variable in the above code it does not work. //var grid = $("#tableVisualization"); It works every alternate call. For example if the whole code was inside a javascript method called LoadGrid(), then the first call to the method works, second call does not, third works, fourth does not and so on. I have seen during debugging, when it reached "grid.jqGrid('GridUnload')" on the even calls, the grid is completely removed(im not sure if the html table is removed or not) and it is not created during "$("#tableVisualization").jqGrid({.....});". Can anyone please explain me the reason for this behaviour. I can make the scenario work because now I am not using a local variable but I would like to know why it does not work?
We can see exactly what is going on within the grid's GridUnload method in grid.custom.js: GridUnload : function(){ return this.each(function(){ if ( !this.grid ) {return;} var defgrid = {id: $(this).attr('id'),cl: $(this).attr('class')}; if (this.p.pager) { $(this.p.pager).empty().removeClass("ui-state-default ui-jqgrid-pager corner-bottom"); } var newtable = document.createElement('table'); $(newtable).attr({id:defgrid.id}); newtable.className = defgrid.cl; var gid = $.jgrid.jqID(this.id); $(newtable).removeClass("ui-jqgrid-btable"); if( $(this.p.pager).parents("#gbox_"+gid).length === 1 ) { $(newtable).insertBefore("#gbox_"+gid).show(); $(this.p.pager).insertBefore("#gbox_"+gid); } else { $(newtable).insertBefore("#gbox_"+gid).show(); } $("#gbox_"+gid).remove(); }); }, The key points to understand are: A new table element is inserted with the same DOM id as the old table. We can see it created in the call to document.createElement('table') and inserted in one of the calls to insertBefore. The existing jqGrid DOM is removed in the call to $("#gbox_"+gid).remove(). Since the old table element is contained within the gbox, it is removed as well. After the call to GridUnload, the DOM element that it refers to no longer exists on the page, so any code that references the element is ineffective. Does that help?
JQGRID - Prevent adding empty row after execution of afterSubmit
I have a grid where I put a custom button in the navgrid for inserting totally different data in another table so I used editGridRow("new",…) where in the php url I just post data to a different table. Actually I am stuck with the issue if I submit the form, even if I settled reloadAfterSubmit:false, it add a new empty row in the grid… You can see the piece of code here: jQuery("#"+child_table_id).navButtonAdd("#"+pager_id, { caption:"Insert",buttonicon:"ui-icon-arrow-1-se", onClickButton:function(){ var rows = jQuery("#"+child_table_id).getRowData(); if ( rows.length != 0 ) { jQuery("#"+child_table_id).editGridRow("new",{height:140,width:420,url:"http://.../edit_datatable.php?table_name=mytable&fact=insert&q=1&flag=yes&ref_id="+id_row, reloadAfterSubmit:false, recreateForm:true, closeOnEscape:true, closeAfterAdd:true, addCaption:'Insert', savekey: [true,13], bSubmit:'Save', afterSubmit:function(response, postdata){ alert('inserting to a total different table...'); return {0:true} } }); } }, position:"last", title:"Insert new step...", cursor:"pointer" }); I tried even to add: onClickButton:function(){ $("#"+child_table_id).setGridParam({ datatype: 'local' }); } afterSubmit:function(response, postdata){ return {0:true} }, onclickSubmit : function(params, posdata) {return {0:true} }, afterComplete:function(response, postdata, formid) { $("#"+child_table_id).setGridParam({ datatype: 'json' }); } but it added anyway a row in the grid… So how I can prevent jqGrid to add a new empty grid and refreshing the grid?…
You wrote about "inserting totally different data in another table", but you add button to the navigator bar of the grid "#"+child_table_id and your code inside of onClickButton callback adds new row to the same grid: jQuery("#"+child_table_id).navButtonAdd("#"+pager_id, { ... onClickButton:function(){ ... jQuery("#"+child_table_id).editGridRow("new", ... } }); If you really want to add new row to another grid you should use id of another in the editGridRow (like jQuery("#"+another_table_id).editGridRow("new",...).
jqGrid - edit data
I am quite new to jquery and jqgrid. I use ASP.NET WebForms. I am able to get some data prom server and show it in grid. I use PageMethods to get data from server. Usually my code is function CreateGrid(){ $("#sestGrid").jqGrid({ datatype: GetData, //toolbar: [true, "top"], colNames: ['Name', 'Age'], colModel: [ { name: 'Name', index: 'Name', width: 170, align: 'left', sortable: false, key: true }, { name: 'Age', index: 'Age', width: 40, align: 'center', sortable: false, editable: true }, ], ondblClickRow: function () { var row_id = $("#sestGrid").getGridParam('selrow'); $('#sestGrid').editRow(row_id, true); } }); } function GetData() { PageMethods.GetSestevalniStevecData(GotData); } function GotData (data) { $("#sestGrid").clearGridData(false); for (var j = 0; j <= data.length; j++) $("#sestGrid").jqGrid('addRowData', j + 1, data[j]); } So, now I would like to edit some data and post it to server. How can I do that using PageMethods? Should I use any other approach? And one more thing. I checked the demos http://trirand.com/blog/jqgrid/jqgrid.html and in all edit examples you are able to edit only one row and then you have to save changes… Is it possible to edit more than one row and save all changes in one step? Thanks all.
jqGrid is designed to be used together with ajax services. So if the user change the data of some row then the changes will be send to the server: to the URL which you configure through jqGrid parameter editurl. So the easiest way to implement row editing will be to include an ASMX web-service or a WCF service in you web site. It is not important whether you use ASP.NET WebForms, ASP.NET MVC or just pure HTML for your pages. So just choose the technology which you prefer and add the corresponding page to your site. The ASMX or WCF should has a method with the signature like public string MyDataEdit (string Age, string oper, string id) (see this old answer for more information). The method should return the id of the new added item (the Name in your case) in case of Add operation. One more small remark. You can change the definition of the ondblClickRow function from function() to function(row_id) and remove the line used getGridParam('selrow').
I used your example and changed it a bit: ondblClickRow: function (rowid) { if (rowid && rowid != lastsel) { changedRows.push(rowid); //keep row id jQuery('#jqgrid').editRow(rowid, true); } } Under the save button click event: $.each(changedRows, function () { var row = $("#jqgrid").getRowData(this); var Id = row['ID']; var price = $(row['Price']).val(); //this is an input type }); HTH someone :)