Fire an event after a local delete jqgrid - events

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!

Related

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.

jqGrid Trying to apply filter(s) on Grid creation

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.

Client side sort not working

I have a jqgrid with the following information:
$("#Table").jqGrid({
url: 'u.json,
loadonce:true,
colNames: msd.rise.columnDisplayNames,
colModel: msd.rise.colModelDef,
gridview: true,
toppager: false,
sortname: 'sd',
sortorder: 'desc',
sortable:true,
loadComplete: function(){
$("#Table").setGridParam({datatype:'json', page:1}).trigger('reloadGrid');
}
});
The client side sort doesn't work. I put loadonce:true and $("#Table").setGridParam({datatype:'json', page:1}).trigger('reloadGrid'); based of this answer. But it still doesn't work. Any idea?
The code of loadComplete which you use currently is wrong. You should never use unconditional .trigger('reloadGrid') inside of loadComplete. Moreover the setting of datatype to 'json' before reloading will makes reloading of data from the server, but you need local reloading to apply sorting. The correct code will be like in the example from the anwer:
loadComplete: function () {
var $self = $(this);
if ($self.jqGrid("getGridParam", "datatype") === "json") {
setTimeout(function () {
$self.trigger("reloadGrid"); // Call to fix client-side sorting
}, 50);
}
}
The code makes reloading only once after the initial loading from the server will be finished.

jqgrid open subgrid only if there is some data

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.

passing csrf token through jqgrid on cell edit

I'm using Codeigniter and jqgrid to build an application. I've recently enabled Codeigniter's builtin CSRF protection for security reasons, and it broke some stuff with jqgrid. I've been able to pass the csrf token when jqgrid is instantiated so all my data loads (by adding the csrf token to the postData), but now anytime I edit a cell I get a 500 error because the csrf token isn't being passed. I can verify this by looking at the post data each time I edit a cell. I read several places that editData is what I want, but adding the token in there doesn't seem to pass it in the edit ajax request. Any ideas?
$("#cust_grid").jqGrid({
url:'/ajax/grid',
datatype: 'xml',
mtype: 'POST',
postData: {<?php echo $this->security->get_csrf_token_name().":'".$this->security->get_csrf_hash()."'"; ?>},
editData: {<?php echo $this->security->get_csrf_token_name().":'".$this->security->get_csrf_hash()."'"; ?>},
colNames:['Name1', 'Name2'],
colModel :[
{name:'name1', index:'name1', width:55, search: true},
{name:'name2', index:'name2', width:110, search: true},
],
pager: '#pager',
rowNum:25,
rowList:[10,25,50,100],
sortname: 'name1',
sortorder: 'asc',
viewrecords: true,
gridview: true,
caption: 'Customers',
height: 600,
width: 1200,
shrinkToFit: false,
altRows: true,
cellEdit: true,
cellsubmit: "remote",
cellurl: "/ajax/editCell",
},
{}
);
It seems that you can solve the problem mostly in the same way like I described here. The main difference is that you use cell editing instead of form editing. So you should use ajaxCellOptions instead of ajaxEditOptions:
ajaxCellOptions: {
loadBeforeSend: function(jqXHR) {
// you should modify the next line to get the CSRF tocken
// in any way (for example $('meta[name=csrf]').attr('content')
// if you have <meta name="csrf" content="abcdefjklmnopqrstuvwxyz="/>)
var csrf_token = '<%= token_value %>'; // any way to get
jqXHR.setRequestHeader('X-CSRF-Token', csrf_token);
}
}
I ended up finding another solution to the problem. I was investigating the cell editing link posted in the another answer and I saw the beforeSubmitCell option. Turns out if you return json data from that function it will be appended to the post data each time a cell is edited. So all I needed to do was add as an option:
beforeSubmitCell: function (rowid,celname,value,iRow,iCol) {
return {<?php echo $this->security->get_csrf_token_name().":'".$this->security->get_csrf_hash()."'";?>}
},
No answer working out after I tried. Then i found the solution for passing CSRF Token from Jqgrid inline editing to Django by using this :
onSelectRow: function(id){
if(id && id!==lastSel){
$(selector).restoreRow(lastSel);
lastSel=id;
}
var editparameters = {
extraparam: {csrfmiddlewaretoken: $('.token-data').data('token')},
keys: true,
};
$(selector).jqGrid('editRow', id, editparameters);
}
Example usage :
http://yodi.polatic.me/jqgrid-inline-editing-integration-with-django-send-csrf-token/

Resources