JqGrid: how to refresh the grid in afterSubmit? - jqgrid

I have two buttons in the pager, one for adding a new record. See the code below:
$(grid_selector).jqGrid('navGrid', pager_selector,
{
edit: false,
add: true,
addicon : 'icon-plus-sign purple',
del: true,
delicon : 'icon-trash red',
search: false,
refresh: false,
view: false,
},
null, //no need for edit
{
//new record form
url: "/add",
...
afterSubmit : function(response, postdata) {
// ??? how to refresh the grid
}
},
...
}
After adding a record, I am hoping to refresh the grid. Could someone let me know how to do this?
I am using local data for the test purpose.
Regards.

Make sure that you are using updated version of jqGrid in your application
If all other parameters are are correct ( refresh:true etc ) you can use this to reload Grid
$(grid_selector).trigger("reloadGrid");
Please note this condition too
The reloading is not performed due to the datatype got change to local(loadonce is true).You need to reload the grid manually in afterSubmit function for form editing. You need to set the datatype to json before triggering reload event.
$(grid_selector).jqGrid('setGridParam',{datatype:'json'}).trigger('reloadGrid');

Default property used in form editing is reloadAfterSubmit: true. It means that jqGrid trigger reloadGrid processing of afterSubmit.
You wrote "I am using local data". It's difficult to answer on your question because you don't posted more full code which you use. I try to guess what you do. Because jqGrid don't support local for editing till now then I suppose that your problem exist because you use loadonce: true option. If the option are used then jqGrid changes the original datatype to "local" after the first loading of data. In other words jqGrid "breaks" connection to the server (to url) after the first loading of data.
So you need just to reset the original datatype ("json" or "xml") before jqGrid trigger reloadGrid. The corresponding code will be about the following:
$(grid_selector).jqGrid("navGrid", pager_selector,
{
edit: false,
addicon : 'icon-plus-sign purple',
delicon : 'icon-trash red',
search: false,
beforeRefresh: function () {
$(this).jqGrid("setGridParam", { datatype: "json" });
}
},
{}, //no need for edit
{
//new record form
url: "/add",
...
afterSubmit: function () {
$(this).jqGrid("setGridParam", { datatype: "json" });
}
},
...
}
The above code add "Refresh" button and uses the same beforeRefresh and afterSubmit. In the way "Refresh" button reloads the data from the server. I personally find existence of such button practical in loadonce: true scenario.

Related

free jqgrid custom formatter lost after sorting or filtering

I am using free jqgrid 4.13.0
I wrote a custom formatter, but unfortunately my cell contents of that column are always lost after sorting the table or filtering. I am probably doing something wrong in the formatter function, but haven't really understood what is missing. Anyone can spot my mistake? Why is it working fine with the built in ones, but not with mine. I got inspired by this one: http://www.ok-soft-gmbh.com/jqGrid/CascadingFormater.htm
I can see how the example is calling $.fn.fmatter.call and maybe I need to do this too. Is this the key? Unfortunately I can't find any documentation on how to do this if I write the function myself.
This is my setup:
var formatEnduser = function (cellValue, options, rowObject, action){
return rowObject.so_enduser_id == undefined ? '' : ''+rowObject.so_enduser_name+'';
}
$("#jqGrid").jqGrid({
datatype: "jsonstring",
datastr: jsonData,
jsonReader: {
root: 'rows',
id: 'crmentity_id',
repeatitems: false,
page: function(obj) { return 1; },
total: function(obj) { return 1; },
records: function(obj) { return obj.rows.length; },
},
autowidth: true,
height: 600,
shrinkToFit: true,
rownumbers: true,
rowNum: 5,
pager: false,
loadonce: true,
viewrecords: true,
colModel: [
{
name: 'crmentity_id',
key: true,
hidden: true
},
{
label: 'Enduser',
name: 'so_enduser_name',
searchoptions: {
sopt : ['cn']
},
formatter: formatEnduser
},
]
});
$('#jqGrid').jqGrid('filterToolbar');
The object jsonData looks like this:
Object { rows=[623], so_total_total=4321, in_total_total=1234 }
In the property rows can be found this:
[Object { crmentity_id="60199", so_enduser_id="6808", so_enduser_name="enduser123", mehr...}, Object { crmentity_id="60136", so_enduser_id="6362", so_enduser_name="userend321", mehr...}, 620 mehr...]
Thanks a lot for any help!
EDIT: I added a jsfiddle to demonstrate the problem, search for end in the filter and see how the data disappears. Sorting does the same. http://jsfiddle.net/tztj9yn7/2/
The main problem is your code is the following. You use datatype: "jsonstring" and the custom formatter uses the property so_enduser_id of the input data, but the property is not a column of the grid. The datatype "jsonstring" will be processed in the same way like the datatype "json" (or "jsonp" or "xml"). It will be read by jqGrid and saved locally only the columns from colModel and jsonReader.id additionally. Thus the property so_enduser_id of the input data will be available in rowObject only during initial reading of the grid. All what I wrote till now is the same for old jqGrid and for free jqGrid.
In case of usage old jqGrid there are two alternative ways to fix the problem:
add hidden column with name: "so_enduser_id"
replace datatype: "jsonstring", datastr: jsonData to datatype: "local", data: jsonData.rows and replace jsonReader to localReader: { id: 'crmentity_id' }. The input data will be saved with all properties (like it be in the input) in case of usage datatype: "local" and the problem will be fixed.
If you would need to load the data directly from the URL then the second way (datatype: "local") will be not possible and the only way will be the usage of hidden columns for all properties which you need later.
Free jqGrid provides you another very simple way: the usage of additionalProperties option. The idea of additionalProperties is very simple. One need sometimes to save some additional properties from every item of input data to use there locally later (because of usage of loadonce: true). Saving the data in DOM is much more expensive as saving the data in the JavaScript structures. One can just use the option like additionalProperties: ["crmentity_id", "so_enduser_id"] to inform free jqGrid to read some other properties and to save there locally. As the result your code will be fixed immediately: see http://jsfiddle.net/tztj9yn7/3/
One more important recommendation about the usage of custom formatters in free jqGrid. There are exist some important problem with the rowObject parameter. It's just the input item exactly like it be in the source. Thus if you would use datatype: "xml" for example then the rowObject parameter would be XML node. In the same way, if you would use repeatitems: true format (["60199", "6808", "enduser123"] instead of {crmentity_id:"60199", so_enduser_id:"6808", so_enduser_name:"enduser123"}) then you will have to use rowObject[1] instead of rowObject.so_enduser_id to access the property so_enduser_id from initial input data. On the next sorting or filtering you will have another format of rowObject (rowObject.so_enduser_id) because of the input data will be the data from the local data parameter. Free jqGrid still use the same format of rowObject parameter to provides the best compatibility with the old versions of jqGrid, but it set additionally rowData property of the options parameter. The options.rowData have always deterministic named format of data and one can use always options.rowData.so_enduser_id independent from the format of the input data and the datatype used. Thus options.rowData is preferred way to access input data. One should't use the third parameter at all. The resulting code of the formatter will be
var formatEnduser = function (cellValue, options) {
var item = options.rowData;
return item.so_enduser_id == undefined ?
'' :
'<a href="index.php?module=Accounts&view=Detail&record=' +
item.so_enduser_id + '">' + item.so_enduser_name + '</a>';
};
See http://jsfiddle.net/tztj9yn7/4/

jqGrid applying sort from known values not working

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.

Apply Custom Formatter after Sort Function with jqGrid

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.

jqgrid retain filter on reload

This question has been as a lot so please forgive me asking again.
I have a grid loaded from a url.
I use loadonce: true
I use filtertoolbar:
$("#status").jqGrid('filterToolbar', { stringResult:true, searchOnEnter:false, autosearch: true, defaultSearch: "cn" });
I have a dropdown search list from which I can select what I'm looking for. Works great.
I have a navbutton I click to initiate a reload every 30 seconds. Works great.
$("#status").jqGrid('navButtonAdd','#statuspager', { caption: '', buttonicon: 'ui-icon-play', onClickButton: function ()
{
stint = setInterval (function() {
postfilt = $("#status").jqGrid('getGridParam', 'postData').filter;
$("#status").jqGrid('setGridParam',{
url: './ar_status.cgi?systemtype=' + systype,
datatype: "json",
postData: postfilt,
search: true,
loadtext: "Refreshing grid...",
loadonce: true,
loadui: "block"
});
$("#status").jqGrid().trigger("reloadGrid");
}, 30000);
},
title: 'Start Auto Refresh (every 30 sec.)'
});
Using google chrome I can see the filters that were specified being posted to the server:
systemtype:production
_search:true
nd:1358887757603
rows:1000
page:1
sidx:system
sord:asc
totalrows:700
filters:{"groupOp":"AND","rules":[{"field":"system","op":"eq","data":"ATTDA02"}]}
I can change the filter between reloads and see the new, even multiple filters:
systemtype:production
_search:true
nd:1358887847592
rows:1000
page:1
sidx:system
sord:asc
totalrows:700
filters:{"groupOp":"AND","rules":[{"field":"system","op":"eq","data":"ATTDA02"},{"field":"dow","op":"cn","data":"MO"}]}
I am using multipleSearch: true on the initial load. I'm pretty sure that's retained on reload
On the grid, the filtertoolbar retains my filter criteria, both text and selects, but when the grid reloads, the filters are ignored and the entire dataset is diplayed in the grid.
I've tried many examples posted here on SO. I've tried adding [{current:true}] to the reloadGrid call - no difference. I can't seem to retain and apply the filters on a reload.
I would like the reload to always return the full dataset from the server (which happens fine), and allow the current filter settings to control what is shown after the reload. I do not want to use the postdata to build a new SQL select statement - server side filtering, because at any time the user may want to click the pause button, select a new filter and view something else from the entire dataset without another reload.
$("#status").jqGrid('navButtonAdd','#statuspager', { caption: '', buttonicon: 'ui-icon-pause', onClickButton: function ()
{
clearInterval(stint);
},
title: 'End Auto Refresh'
});
How can this be done without using cookies, as I saw in one post?
I could try using jqGridExport'ing the postfilt var, and then jqGridImport'ing it but was hoping for a more direct approach. I'm not even sure this would help since I already have everything I need right here in the grid via postData.
As a side note, in my setGridParam above, the loadtext I specify is never displayed. Instead, the default "Loading..." is displayed. All of the other parameters are working.
Many thanks in advance,
Mike
Solution. The complete loadComplete to retain filters, sort index and sort order after a [json] reload from the server:
loadComplete: function() {
var $this = $(this);
postfilt = $this.jqGrid('getGridParam','postData').filters;
postsord = $this.jqGrid('getGridParam','postData').sord;
postsort = $this.jqGrid('getGridParam','postData').sidx;
if ($this.jqGrid("getGridParam", "datatype") === "json") {
setTimeout(function () {
$this.jqGrid("setGridParam", {
datatype: "local",
postData: {filters: postfilt, sord: postsord, sidx: postsort},
search: true
});
$this.trigger("reloadGrid");
}, 50);
}
}
Thanks very much!!!!
I only added a bit to your solution to retain the page number as well:
loadComplete: function () {
var $this = $(this);
var postfilt = $this.jqGrid('getGridParam', 'postData').filters;
var postsord = $this.jqGrid('getGridParam', 'postData').sord;
var postsort = $this.jqGrid('getGridParam', 'postData').sidx;
var postpage = $this.jqGrid('getGridParam', 'postData').page;
if ($this.jqGrid("getGridParam", "datatype") === "json") {
setTimeout(function () {
$this.jqGrid("setGridParam", {
datatype: "local",
postData: { filters: postfilt, sord: postsord, sidx: postsort },
search: true
});
$this.trigger("reloadGrid", [{ page: postpage}]);
}, 25);
}
}
I am not sure, but I suppose that the origin of your first problem could be mixing postData.filters and postData and usage filter property instead of filters``. You use
postfilt = $("#status").jqGrid('getGridParam', 'postData').filter;
to get filter property instead of filters. You get undefined value. So the setting postData to postfilt means nothing.
The next problem is that the server response contains non-filtered data. To force filtering the data locally you have to reload the grid once after the loading from the server have finished. You can do this inside of loadComplete. Exactly here you can set postData.filter if required, set search: true and trigger reloadGrid event. It's important only to do this once to have no recursion and you must don't set datatype back to "json" in the case. The datatype will be changed to "local" and the end of loading from the server in case of usage loadonce: true option. If you want apply filtering locally you have to reload grid once with options datatype: "local", search: true and postData having filters specifying the filter which need by applied. See the code from the answer or another one which do another things, but the code which you need will be very close.

Fire an event after a local delete jqgrid

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!

Resources