I have a jqGrid and want to apply user's sort values after it loads. These values are saved and retrieved in jquery cookies. I am storing data in cookies because user will go to another url and come back which initiates page load and they want to be in same spot they left.
I have a loadPreferences function being called within loadComplete.
See code snippet below(I left several jqrid properties out to keep posting short).
// Set up the jquery grid
$("#jqGridTable").jqGrid(
{
// Ajax related configurations
url: jqDataUrl,
datatype: "json",
mtype: "GET",
autowidth: true,
// Configure the columns
colModel: columnModels,
// Grid total width and height
height: "100%",
// customize jqgrid post init
gridComplete: function()
{
CRef.updateJqGridPagerIcons("jqGridTable");
},
// Default sorting
sortname: "LastName",
sortorder: "asc",
sorttype: "text",
sortable: true,
jsonReader:
{
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
userdata: "userdata"
},
loadComplete: function (data)
{
if (boolPreferencesLoaded == false)//page level variable
{
boolPreferencesLoaded = loadPreferences(this);
$("#jqGridTable").trigger("reloadGrid");
}
isGridSorting(this, false);
}
...the rest of grid properties...
and in the function call(which is located in another js file), I have...
function loadPreferences(gridId)
{
if (typeof $.cookie("sortCol") !== "undefined")
{
$(gridId).jqGrid("sortGrid", $.cookie("sortCol"), true, $.cookie("sortOrd"));
}
return true;
}
function isGridSorting(gridId, sorting)
{
$.cookie("sortCol", $(gridId).jqGrid('getGridParam', 'sortname'));
$.cookie("sortOrd", $(gridId).jqGrid('getGridParam', 'sortorder'));
$(gridId).jqGrid('setGridParam', { postData: { isSorting: sorting } });
}
My problem is when I go to apply them on page load(with jqGrid specified above), it does not exactly work. The icon moves to correct column and the arrow is pointing in correct direction, but the data in column does not sort.
I know there are a lot of posts dealing with similar issues, but not able to get solutions to work. What I am trying to do seems to easy, but it's driving me nuts. If you respond, please make comment easy to understand. Thank you.
Related
I have an object that contains the following filter string:
prefs.filters={"groupOp":"AND","rules":[{"field":"FirstName","op":"cn","data":"max"}]}
Here is my grid create, where I am trying to apply the filters in the postData setting:
// Set up the jquery grid
$("#jqGridTable").jqGrid(
{
// Ajax related configurations
url: jqDataUrl,
datatype: "json",
mtype: "GET",
autowidth: true,
// Configure the columns
colModel: columnModels,
// Grid total width and height
height: "100%",
// customize jqgrid post init
gridComplete: function()
{
CRef.updateJqGridPagerIcons("jqGridTable");
},
// Paging
toppager: true,
rowNum: 20,
rowList: [5, 10, 20, 50, 100],
viewrecords: true, // Specify if "total number of records" is displayed
// Default sorting
sortname: typeof prefs.sortCol !== "undefined" ? prefs.sortCol : "LastName",
sortorder: typeof prefs.sortCol !== "undefined" ? prefs.sortOrd : "asc",
sorttype: "text",
sortable: true,
postData: typeof prefs.filters !== "undefined" ? { filters: prefs.filters } : {},
//also tried this...
//postData: typeof prefs.filters !== "undefined" ? { JSON.stringify(filters: prefs.filters) } : {},
//remaining property settings excluded from post to keep short.
Update: Using .navGrid on grid as follows:
.navGrid("#jqGridTable",
{ refresh: true, add: false, edit: false, del: false, refreshtitle: getRefreshText('#Model.Instruction'), searchtitle: searchText },
{}, // settings for edit
{}, // settings for add
{}, // settings for delete
{ closeAfterSearch: true, closeOnEscape: true, multipleSearch: true, multipleGroup: true });
When grid is created, the filter in postData is not applied. I also tried triggering reload event after the initial create and that to did not apply filter either.
From other posts, I believe I'm on correct path, but appear to be missing something.
Update after comments:
I added the following code to loadComplete...
if ($("#jqGridTable").jqGrid("getGridParam", "datatype") === "json") {
setTimeout(function () {
$("#jqGridTable").jqGrid("setGridParam", {
datatype: "local",
postData: { filters: prefs.filters, sord: prefs.sortOrd, sidx: prefs.sortCol },
search: true
});
$("#jqGridTable").trigger("reloadGrid");
}, 50);
}
and it successfully retains the filters. :)
However, now I have interesting issue side effect. I can sort on columns and some columns will change to sort asc/desc correctly, but when I go to others and sort, they sort but in the order that they originally loaded which is neither asc or desc.
You have to set search: true option of jqGrid if you want that filters will be applied. Moreover you use datatype: "json". It means that the filters will be just send to the server and your server code have to decode the filters and to use there. One more remark. The correct value for postData would be { filters: JSON.stringify(prefs.filters) }.
UPDATED: I recommend you upgrade to the latest version (4.12.1) or free jqGrid. It's the fork of jGrid which I develop since the end of 2014. To use free jqGrid you can just change the URLs to jqGrid files to URLs described in the wiki article. After that you can use the following options:
loadonce: true,
forceClientSorting: true,
search: true,
postData: { filters: prefs.filters },
sortname: prefs.sortCol,
sortorder: prefs.sortOrd
and remove the loadComplete code which you posted in "Update after comments" part of your question. Free jqGrid will load all data returned from the server, apply the filter prefs.filters locally, sort the results locally and display the first page of the results (based on the page size rowNum: 20).
The old demo loads the JSON data from the server, sort the data locally and filter by isFinal === 1 and finally display the first page of results. The demo uses additionally custom sorting using sortfunc, additionalProperties, which allows to saved additionally properties in local data.
You can additionally include reloadGridOptions: { fromServer: true } to other options of navGrid which you use (refresh: true, add: false, ...). It will change the behavior of the Refresh button of the navigator bar to reload the data from the server if the user clicks on the button. See another answer, which I posted today for more information about new options of free jqGrid and loadonce: true.
I am using a custom control on an Xpage to build a table with jqGrid. The jqGrid receives the data via JSON and fills the table correctly.
My question is with the sort function of jqGrid. I apply a custom formatter to the cell value of my "docname" column when the table first builds. The issue that I am having is after sorting any of the columns this formatter becomes unusable. The format is still applied but this particular formatter builds a url that launches another Xpage and relies on the parameter "docid".
Here is my custom formatter:
function openDocument(cellvalue, options, rowObject) {
return "<a target='#{javascript:compositeData.target}' title='Open Document'
href='https://test.url.com?DocID=" +rowObject["docid"]+
"&action=#{javascript:compositeData.action}' class='doclink'>"
+ cellvalue + "</a>"; }
Is there any way to get the rowObject "docid" back into the openDocument formatter after sorting the grid?
I researched some and found the onSortCol event and have it initialized like this:
onSortCol: function(index,iCol,sortorder) {alert("Test")}
My alert that I have in the onSortCol initilization is working, I just need to find out how to set my "docid" parameter after the sort is run since it is currently set to undefined after the sort.
I have tried putting in:
{rowObject["docid"]}
But this just breaks the sorting all together.
I have also read these posts:
onSortCol Event
JQGrid Sorting - how to trigger onSortCol event
jqGrid - Is it possible to set onSortCol after init?
Thanks for your help.
Edit:
jqGrid Definition:
$().ready(function(){
jQuery("#listxGrid").jqGrid({
url:'#{javascript:compositeData.url}',
datatype: "json",
colNames:#{javascript:compositeData.colNames},
colModel:#{javascript:compositeData.colModel},
shrinkToFit: false,
jsonReader: {
repeatitems: false,
id: '#{javascript:compositeData.colID}',
root: function (obj) {
if ($.isArray(obj)) return obj;
if ($.isArray(obj.items)) return obj.items;
return [];
},
page: function () { return 1; },
total: function () { return 1; },
records: function (obj) {
if ($.isArray(obj)) return obj.length;
if ($.isArray(obj.items)) return obj.items.length;
return 0;
}
},
gridview: true,
loadonce: true,
ignoreCase: #{javascript:compositeData.ignoreCase},
rowNum: #{javascript:compositeData.rowNum},
rowList: #{javascript:compositeData.rowList},
rownumbers: #{javascript:compositeData.showRowNumbers},
height: #{javascript:compositeData.height},
caption: '#{javascript:compositeData.caption}',
pager: '#pagerxGrid',
viewrecords: true,
emptyrecords: '#{javascript:compositeData.emptyRecords}',
sortable: true,
onSortCol: function(index,iCol,sortorder) {alert(index)},
grouping: #{javascript:compositeData.grouping},
groupingView : {
groupField : #{javascript:compositeData.groupField},
groupDataSorted : true,
groupColumnShow : #{javascript:compositeData.showGroupCol}
}
});
Have a look at this answer which suggests the use of isArray to determine whether to use rowObject["docid"] or rowObject[integer]:
jqGrid - rowObject inconsistencies?
I ended up solving the problem this way. On the jqGrid it was receiving the "docid" param from the remote data on the first load just fine but as soon as the sort function called it would be set to "undefined."
As #PerHenrikLausten pointed out with his link, after the onload function completes this remote data type is then switched to local data. By loading in the docid into a hidden column, this is then available as a parameter for my formatter after the data type is switched.
By adding:
'Docid' as a colName & {name:'docid', index:'docid', hidden: true} to the colModel
It allows me to sort the jqGrid from any of my columns that I have sortable set to true with the docid parameter as what it should be not "undefined."
Thanks everyone for your input.
We have performance issues with JQgrid rendering. Please advise.
JQGrid v4.3.2, jquery-1.7.2.min.js, jquery-ui-1.8.1.sortable.min.js, jquery-ui-1.8.20.custom.min.js
Browser: IE6,7
Every user is shown data in 2 grids - actions and fyi's. Typical data range is ~300 rows in each grid. The list of columns could vary for user groups and hence the colModel structure is dynamic. After getting data we apply conditional styles to each row (to be bold or not etc) and change the number formatting.
Code sample for grid is as below:
jQuery('#ActionItems').jqGrid({
url: 'http://actionsurl',
mtype: 'GET',
datatype: 'json',
page: 1,
colNames: actionsColNames,
colModel: actionsColModel,
viewrecords: true,
loadonce: true,
scrollrows: false,
prmNames: { id: "PrimaryID" },
hoverrows: false,
jsonReader: { id: "PrimaryID" },
sortname: 'CreateDt',
sortorder: 'desc',
gridComplete: function () {
fnActionsGridComplete();
},
recordtext: "Displaying {1} of {2} Records",
emptyrecords: "No data to view",
emptyDataText: "No data found.",
loadtext: "Loading...",
autoWidth: true,
rowNum: 1000,
grouping: true,
groupingView: groupingViewOp
});
Formatting code in fnActionsGridComplete():
Set column widths in %
Iterate thru rows to apply conditional css styles
$("#Actions").find("tbody tr").each(function () {
if ($(this)[0].id != '') {
var data = $(this).find('.IsItemNew').html();
if(data == "Y") {
$(this).css("fontWeight", "bold");
}
}
});
Formatting for specific columns.
Currently we have performance issues for >200 rows of data in any grid. After analysis we found that formatting and rendering is taking most time.
Can you suggest any optimal way to improve performance here. (paging is no-no)
Regards,
Rajani
- We did testing on IE9 and its lot better. But users cant immediately upgrade.
The reason is the code fnActionsGridComplete. I recommend you to read the answer which explains why it's very important to use gridview: true and reduce the number of changes of DOM elements of the page.
What you try to do seems could be implemented by adding cellattr to the column "IsItemNew". The code could be about the following
cellattr: function (rowId, value) {
// additional parameter of cellattr: rawObject, cm, rdata are optional
if (value === "Y") {
return ' style="font-weight:bold;"';
}
}
Alternatively you can add class attribute instead of style and define font-weight: bold in the class.
I recommend you to read the answer, this one, this one etc. If you would need to set some properties on the whole row instead of the cell only you can use rowattr (see the answer).
If you would include gridview: true and use cellattr, rowattr or custom formatters you would see that the performance of the grid will be on absolutely another level.
here is declarations of my subgrid:
subGrid : true,
subgridtype: 'json',
subGridUrl: 'manuf_subgr.php',
subGridModel: [{ name : ['Package','Sticker','Manufacturer'],
width : [85,50,100],
params: ['Catalogue']
}
],
gridComplete: function() {
var timeOut = 50;
var rowIds = $("#schedule").getDataIDs();
$.each(rowIds, function (index, rowId) {
if(rowId.row_cnt != 0){
setTimeout(function() {
$("#schedule").expandSubGridRow(rowId);
}, timeOut);
timeOut = timeOut + 200;
}
});
}
what I expect to happen is this line if(rowId.row_cnt != 0) preventing opening a subgrid if there is no data returned from json... yet all grids are open regardless...
can someone help to implement stop for opening empty subgrids?
full code:
jQuery("#schedule").jqGrid({
url:'sched.php',
datatype: "json",
mtype:'GET',
colNames:['Street_Date','Label','Catalogue', 'Artist', 'Title','UKDP','UPCEAN','format'],
colModel:[
{name:'Street_Date',index:'Street_Date desc, ID', sorttype:"date", formatter:'date', formatoptions: {newformat:'d/m/Y'}, width:75},
{name:'label',index:'label', width:100,align:"center"},
{name:'Catalogue',index:'Catalogue', width:85},
{name:'Artist',index:'Artist', width:120},
{name:'Title',index:'Title', width:250},
{name:'UKDP',index:'UKDP', width:35, align:"right", formatter:"number", sorttype:"float"},
{name:'UPCEAN',index:'UPCEAN', width:120, align:"center"},
{name:'format',index:'format', width:70, sortable:false}
],
height: "100%",
rowNum:20,
rowList:[10,20,30,50,100],
sortname: 'id',
viewrecords: true,
sortorder: "desc",
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: true,
cell: "cell",
id: "id",
userdata: "userdata",
subgrid: {root:"rows", repeatitems: true, cell:"cell" }
},
pager: '#schedule_pager',
caption:"Release Schedule",
grouping:true,
groupingView : {
groupField : ['Street_Date']
},
subGrid : true,
subgridtype: 'json',
subGridUrl: 'manuf_subgr.php',
subGridModel: [{ name : ['Package','Sticker','Manufacturer'],
width : [85,50,100],
params: ['Catalogue']
}
],
gridComplete: function() {
var timeOut = 50;
var rowIds = $("#schedule").getDataIDs();
$.each(rowIds, function (index, rowId) {
if(rowId.row_cnt != 0){
setTimeout(function() {
$("#schedule").expandSubGridRow(rowId);
}, timeOut);
timeOut = timeOut + 200;
}
});
},
onSelectRow: function (rowId) {
$("#schedule").jqGrid ('toggleSubGridRow', rowId);
}
});
You write in the comment that you are newbie and it's the second day when you use it. jqGrid is relatively complex and your first example which you try to implement seems to me too complex for newbie. You try to load fill jqGrid with the data from the database and do grouping and subgrid in one grid.
What you try to implement in your demo can be solved by usage of expandOnLoad: true property of the subGridOptions option:
subGridOptions: {expandOnLoad: true}
You can see the feature on the official demo disguised under "Hierarchy" / "Expand all Rows on load". There are one important problem which I described in the answer. The problem is shortly the following: internal implementation of Ajax requests used in jqGrid prevent (skip) Ajax requests when another pending (not yet answered by the server) are working (see .grid.hDiv.loading in the places of the code here, here in the subgrid module and here, here and here). Neither expandOnLoad: true nor your current implementation can grantee that new Ajax request will be started during previous one still not responded. So you can have not all subgrids opened. You main question: "how to prevent opening of empty subgrids or how to hide it?", I find the second (and less important) question. Even if you see currently that your web site opens all subgrids it can be that access to the same site from more far place from the internet will follow opening of one or some subgrids only.
So I think that you should either change the design of your web page (change what you want to display in subgrids) or change the implementation so that you construct a queue with the list of subgrids which should be opened and you will open the next grid only after the previous one will be opened.
Alternatively you can includes the data for all subgrids in the response for the main grid. In the case you should use subGridRowExpanded callback to fill the grids as subgrid as grid. You you would use no caption and no pager option in the subgrids you will be get the same look as with the standard subgrids. Additionally you will have much more flexibility in the options. I personally prefer to subgrid as grid.
So what I am trying to do is fire an event AFTER a local delete has been done on the jqgrid. The reason for this is because I am dealing with a global save on the website so I am not posting directly to the server. I am storing the data in JSON form within a hidden element on the page so when the user finally saves the element value is grabbed and sent to the server along with all the other data.
The issue I am having is that when I delete a row from the jqgrid I am not able to update the hidden element with the change, so if the user saves after that it is like the remove never happened.
$("#translationMappingGrid").jqGrid({
data: mydata,
datatype: "local",
mtype: 'GET',
colNames:['From','To', 'Type'],
colModel :[
{name:'from',index:'from', width:180, align:"left",sorttype:"float", editable: true, editrules:{custom:true, custom_func:validateIPGridInput}},
{name:'to',index:'to', width:180, align:"left",sorttype:"float", editable: true, editrules:{custom:true, custom_func:validateIPGridInput}},
{name:'type',index:'type', width:200,align:"left",sorttype:"float", editable: true,
edittype:"select", formatter:'select', editoptions:{
value:"0:Never Translate;1:Always Translate;2:Only If Source;3:Only If Destination"}
},
],
pager: '#pager',
rowNum:10,
rowList:[10,20,30],
sortname: 'invid',
sortorder: 'desc',
viewrecords: true,
gridview: true,
caption: 'Mapping',
editurl: 'probe.sysinfo.ajax',
url:'clientArray',
onSelectRow: function(id){
jQuery('#translationMappingGrid').jqGrid('restoreRow',lastsel2);
//below are the parameters for edit row, the function is called after a successful edit has been done
//jQuery("#grid_id").jqGrid('editRow',rowid, keys, oneditfunc, succesfunc, url, extraparam, aftersavefunc,errorfunc, afterrestorefunc);
jQuery('#translationMappingGrid').jqGrid('editRow',id,true,"","","","",function () {
setTranslationMappingJSON(getGridDataJSONString(this));
window.parent.document.getElementById('notificationDiv').style.display= "";
});
lastsel2=id;
},
afterInsertRow: function(rowid, rowdata, rowelem ){
//alert("after insert row");
setTranslationMappingJSON(getGridDataJSONString(this));
window.parent.document.getElementById('notificationDiv').style.display= "";
}
});
//adds buttons to jqgrid nav bar
jQuery("#translationMappingGrid").navGrid('#pager',{
edit:false,add:true,del:true,search:false,refresh:true
}, {
closeAfterAdd:true,
closeAfterEdit: true
},
{
closeAfterAdd:true,
closeAfterEdit: true,
afterSubmit: function(response, postdata) {
alert("after complete row");
setTranslationMappingJSON(getGridDataJSONString(this));
window.parent.document.getElementById('notificationDiv').style.display= "";
return [true,""];
}
});
As indicated in the code above I am successfully updating the hidden element with the changes on both add and edit (inline) via afterrestorefunc, but this is not working for delete.
I have tried using afterSubmit in the code above, but this is not working either. I have been working on this for a few days now and have come to the conclusion that I might have to write my own custom code for the delete button entirely, but I am hoping this is not the case.
The OP wrote in an edit:
So it appears as though I was staring at the issue for too long and was missing the obvious....lucky me. I found out two things:
Using afterSubmit was the wrong thing to use, instead I should be using afterComplete.
I had tried using afterComplete before trying afterSubmit and the reason it was not working it because I am putting them both within the "add" parameters and NOT the delete. Once again, I feel pretty awesome for that one :)
Well now that I have figured that out here is the code snippet that saved my life:
jQuery("#translationMappingGrid").navGrid('#pager',{
edit:false,add:true,del:true,search:false,refresh:true
}, {
closeAfterAdd:true,
closeAfterEdit: true
},
{
closeAfterAdd:true,
closeAfterEdit: true
},{
afterComplete:
function () {
//saves the changed JSON string to the hidden element
setTranslationMappingJSON(getGridDataJSONString(jQuery('#translationMappingGrid')));
window.parent.document.getElementById('notificationDiv').style.display= "";
}
});
This is tested and the function is called after the delete has been performed and saves the local changes to my hidden element.
For anyone who is curious about what the format is:
/* The following is the setup
navGrid(<name>, {<buttons, true/false},
{
<edit parameters>
},
{
<add parameters>
},
{
<delete parameters>
}
*/
Thanks for everyone who might have started working on this, and definitely thanks to the developers of jqgrid. Best javascript grid I have ever worked with!