How to supply a Row ID when using jqGrid 'editGridRow' to create a new row and not the auto generated Row ID jqg1 - jqgrid

I'm new to jqGrid, so hopefully someone can point me in the right direction.
Basically, I am using jgGrid to display a list of dates and costs that I have read in from a file that I want the user to be able to amend or add new entries or delete existing entries. Upon the user clicking an onscreen button "Apply" to post back the form , I read out the jqGrid and post back to Server in the form of a JSON string.
My problem is that when I add new rows (via 'editGridRow'), jqGrid is using it's autogenerated jqg1, jg2, jg3, etc and the new rows are being populated at the top of grid instead of at their row id position i.e at the bottom of grid.
I am able to generate RowID's as necessary, however I do not seem to be able to supply them to 'editGridRow' when creating new entries, instead it appears I have to use the keyword "new".
As you are aware the reason I am using editGridRow instead of addRowData is that editGridRow creates a modal dialog for the user to enter the data.
Any help would be appreciated.
This is what I would like to use to supply a row ID:
$("#tableGrid").jqGrid('editGridRow', gridRowID, {reloadAfterSubmit:false});
This is what I have to use to get the code to work:
$("#tableGrid").jqGrid('editGridRow', "new", {reloadAfterSubmit:false});
Here is the code snippet I use for creating the gqGrid in my JSP:
var gridRowID = ${costHistoryEntries}.length
$("document").ready(function() {
$("#tableGrid").jqGrid({
data: ${costHistoryEntries},
datatype: "local",
height: 200,
colNames:['Date', 'Cost'],
colModel:[
{name:'chdate', index:'chdate', width:110, sorttype:"date", editable:true, editrules:{date:true, required:true, custom:true, custom_func:checkDate}, datefmt:'d/m/Y'},
{name:'cost', index:'cost', width:160, align:"right", sorttype:"float", editable:true, editrules:{number:true, required:true}, formatter:'float'},
],
autowidth: true,
loadonce: true,
sortname: 'chdate',
sortorder: "desc",
rowList:[10, 20, 30],
pager: jQuery('#tablePager'),
viewrecords: true,
editurl: '/myurl',
caption: "Cost History Entries" }
);
$("#tableGrid").jqGrid('navGrid', "#tablePager", {edit:true, add:true, del:true, search:true, refresh:true});
$("#addEntry").click(function() {
gridRowID++;
$("#tableGrid").jqGrid('editGridRow', "new", {reloadAfterSubmit:false});
});
});
I also created a button and linked it to "addEntry" as an alternative way to adding a new row using the jqGrid Navigator "add/edit/delete/find/reload" bar. As you can see previous to loading the grid with data I stored the number of entries in gridRowID. What I was hoping to be able to do in the "#addEntry" click function was use the updated gridRowID as a RowID parameter.
As a FYI:
In a previous version of the code I was using the following to load the data into the grid:
var griddata = ${costHistoryEntries};
for (var i=0; i <= griddata.length; i++) {
$("#tableGrid").jqGrid('addRowData', i+1, griddata[i], "last");
}
but found that I could do that same with
data: ${costHistoryEntries},
Both versions correctly create row ID's for the supplied sample data from the server:
[{"chdate":"20/05/2011","cost":"0.111"},{"chdate":"01/06/2011","cost":"0.222"},{"chdate":"07/07/2011","cost":"0.333"}]
My problem is adding new rows of data.
Further update, On the server side, as a test I intercepted the post to /myurl and updated the id from "_empty" to "7" but the new entry in jqGrid still has an autogenerated jqGrid Row ID "jqg1":
Key = chdate, Value = 26/09/2011
Key = oper, Value = add
Key = cost, Value = 14
Key = id, Value = _empty
Updated Key = chdate, Value = 26/09/2011
Updated Key = oper, Value = add
Updated Key = cost, Value = 14
Updated Key = id, Value = 7

I am not quite understand your requirement. You get the input for the jqGrid from the server, but use datatype: "local" instead of the datatype: "json" for example which instruct jqGrid to get ajax request to the server to get the data whenever as needed. Moreover you want to save the date on the server, but use editurl: '/dummyurl' instead of the real server url. The editurl would get the input data from the $("#tableGrid").jqGrid('editGridRow', "new", {reloadAfterSubmit:false}); and should post back the id of the new generated row. Is it not what you want?
So my suggestion would be to use some server based datatype (the bast is datatype: "json") and in the same way use real editurl which save the data on the server (in the database mostly) and place in the server response the id on the new generated data item.
UPDATED: If you use reloadAfterSubmit: false option of the editGridRow you have to use afterSubmit event handler together with reloadAfterSubmit which decode the server response and return the result in the format [true,'',new_id] For example if your server just return new rowid as the data you can use
$("#tableGrid").jqGrid('editGridRow', "new",
{
reloadAfterSubmit: false,
afterSubmit: function (response) {
return [true, '', response.responseText];
}
}
);

Related

JqGrid Performance - setRowData lags

setRowData takes almost 5 seconds when the grid has 300 rows, 30 cols, and 4 frozen cols.
$("#tbl").jqGrid({
gridview: true,
url: '../controller/GetData',
datatype: "json",
rowNum: pageSize,
viewrecords: true,
loadtext: '',
loadui: 'disable',
rowList: [1000, 2000, 3000],
width: $(window).width() - LeftMargin,
shrinkToFit: false,
pager: '#dvPager',
pagerpos: 'left',
colNames: GetColNames(selectedViewName, viewCols),
colModel: GetColModel(selectedViewName, viewCols),
cmTemplate: {
title: false
},
recordtext: "Displaying {0} - {1} of {2}",
rowattr: function (rowData) {
},
//onCellSelect: function (rowid, iCol, cellcontent, e) {
// e.stopPropagation();
// proto.editcell(rowid, iCol, cellcontent, e);
//},
loadComplete: function (data) {..},
onPaging: function (data) {..},
serializeGridData: function (postData) {..}
});
Can you please guide me with the performance tuning tips?
In GetColModel we are binding columns as follows -
'Discount': {
name: 'Discount', index: 'Discount', width: colModelWidthDict['Discount'], title: false, sortable: false, resizable: colResizable, hidden: !bReadCalculationSellInfo,
formatter: function (cellValue, option, rowObject) {
if (rowObject.level == 0 || (rowObject.Flag == 0 && (rowObject.Discountable && rowObject.Discountable.toLowerCase() == 'no')))
return '';
else {
if (!proto.IsReadOnly(rowObject) && ((rowObject.Flag == 0 && (rowObject.Discountable && rowObject.Discountable.toLowerCase() == 'yes')) || rowObject.Flag > 0))
return proto.GetControls("Discount", option.rowId, "Numeric", rowObject.Discount, 6, 90)
else
return '<span class="amt">' + cellValue + '</span>';
}
},
unformat: function (cellValue, option) {
return cellValue;
},
cellattr: function (rowId, val, rowObject, cm, rdata) {
if (parseInt(rowObject.PPPChngDisc) == 1)
return ' style="color:red"';
}
}
//code for colModel - 1 column above
In general you should prefer to modify only small number of rows. If you modify one row then the web browser have to recalculate position of all other rows (500 rows) of the grid. In the case modifying 300 rows means 300*500 operations for the web browser.
If you fill the whole grid and you use gridview: true option then jqGrid places at the beginning all the data for the grid body in array of strings. After preparing of all information in string format jqGrid place the whole body of the grid as one operation. It's just one assigning innerHTML property of tbody. Thus it's more effective to reload the whole grid as to make modification of many rows of the grid in the loop using setRowData.
So I would recommend you to reload the grid in your case.
Moreover you should consider to reduce the number of rows in the page of grid. If you use rowNum: 500 you just reduce the performance of your page tin many times without any advantage for the user. The user can see about 20 rows of the data only. Only if the user scrolls he/she is able to see another information. In the same way the user could click next page button. Holding 500 rows force web browser make a lot of unneeded work. Modifying of the first row from 500 the web browser have to recalculate position of all 500 rows. Even if the user move the mouse over a row the web browser change the class of the hovering row and it have to recalculate position of all other from 500 rows event the rows are not visible.
One more remark. The implementation of frozen columns in jqGrid 4.6 is slow. Starting with the end of 2014 and publishing 4.7.1 with changing Lisanse and making jqGrid commercial I develop free jqGrid as fork based on jqGrid 4.7 (see the readme for more details). I implemented a lot of changes and new features in the fork. The recent changes includes many improvement of frozen columns feature. If you loads free jqGrid or just try it directly from GitHub by including the corresponding URLs (see the wiki) you will see that the performance of frozen columns is dramatically improved. Additionally frozen columns supports now row and cell editing in all editing modes. I plan to publish free jqGrid 4.9 soon. So I recommend you to try it.
UPDATED: You posted the code, which you use in comments below. I see the main problem in the implementation of Process function which will be called on change in the <input> fields on the grid. I recommend you to try something like this one:
function Process(contrl) {
var $cntrl = $(contrl),
$td = $cntrl.closest("tr.jqgrow>td"),
$tr = $td.parent(),
rowId = $tr.attr("id"),
newValue = $cntrl.val(),
$grid = $("#list"),
p = $grid[0].p,
colModel = p.colModel,
columnName = colModel[$td[0].cellIndex].name, // name of column of edited cell
localRowData = $grid.jqGrid("getLocalRow", rowId),
iColTotal = p.iColByName.total;
// modify local data
localRowData[columnName] = newValue;
localRowData.total = parseInt(localRowData.quantity) * parseFloat(localRowData.unit);
// modify the cell in the cell (in DOM)
//$grid.jqGrid("setCell", rowId, "total", localRowData.total);
$($tr[0].cells[iColTotal]).text(localRowData.total);
return false;
}
One can event improve the code and not use setCell at all. It's important to understand that local grid hold the data in the form of JavaScript object. The access to the data is very quickly. You can modify the data without any side effects existing with DOM elements. In the above code I use only relative search inside of the DOM of the row using closest and parent. It works very quickly. I recommend to save $("#list") in the variable outside of the Process (move var $grid = $("#list") in the outer function) and just use $grid variable. It will make access to the DOM of page very quickly. The line localRowData = $grid.jqGrid("getLocalRow", rowId) get the reference to internal JavaScript data object which represent the internal data of the row. By modifying the data by localRowData[columnName] = newValue; or localRowData.total = ... we make the half of job. One need only to change the value in the DOM on the cell Total. I used iColByName which exist in the latest sources of free jqGrid on GitHub. It get just the column index in colModel by column name. One can find the same information alternatively if one use more old jqGrid. The line $($tr[0].cells[iColTotal]).text(localRowData.total); shows how to assign manually the data in the cell. It's the most quick way to do this, but one assign the data without the usage formatter. For more common case (for example in case of frozen "total" column) one can use the commented row above: $grid.jqGrid("setCell", rowId, "total", localRowData.total);.

How to edit OndemandGrid and update to the JSONRest Store

The JsonRest store I created is shown below
var questionBaseURL = "/" + contextName + "/service/questions/" + projectId + "/";
var questionStore = new dojo.store.JsonRest({
target: questionBaseURL,
handleAs: 'json',
idProperty: 'questionId'
});
questionStore = new dojo.store.Observable(questionStore);
var memoryStore = new dojo.store.Memory();
var questionCacheStore = new dojo.store.Cache(questionStore, memoryStore);
Which I use to render into the Grid created as below
var CustomGrid = declare([OnDemandGrid, Keyboard, Selection]);
var questionGrid = new CustomGrid({
store: questionCacheStore,
columns: [
editor({
label: "Questions",
field: "question",
editor: "text",
editOn: "dblclick",
sortable: true,
autoSave:true
})
],
selectionMode: "single",
cellNavigation: false
}, "questions");
questionGrid.startup();
questionGrid.renderArray(questionArray);
The data is properly populated in the grid. Now, since am using "editor", I am able edit the populated data in the grid. I am not sure how exactly to detect if the data has been edited (dirty data ) and which method to call to carry the updated data back to the server. I couldn't find any easy documentation. So any help is appreciated. Thanks in advance
You can use the grid's save method to push all items with dirty data back to the server. There is also a revert method which can be called to discard any dirty data. These are listed in the OnDemandList and OnDemandGrid documentation.
These methods are defined in dgrid/_StoreMixin which is inherited by OnDemandList (and OnDemandGrid). The editor column plugin calls updateDirty (also defined by _StoreMixin) when changes are made, which updates a dirty hash. save will check this hash and call put on the store for each dirty item.

jQgrid change paramaters sent to server

I am using cookies to load a users previous sorting and paging options. I would like to take those saved values, and set them as the parameters the server receives.
The paramaters I wish to change are as follows, (rows are replaced by max via prmNames)
/&max=20&page=1&sidx=&sord=asc
I have tried using:
$.extend($.jgrid.defaults, {
sidx:"fName",
sord:"desc",
page:2,
rows:10});
and variations of:
beforeRequest:function(){
$('#grid').jqGrid('setGridParam', {
sidx: "fName",
sord: "desc",
page: 2,
max: 10
});
}
It changes the value for page using $.extend($.jgrid.defaults... , but I cannot get the other parameters to change.
You need just use setGridParam to set parameters of jqGrid which have another names as sidx, sord, page and rows.
sidx -> sortname
sord -> sortorder
page -> page
rows -> rowNum
So the best would be to create jqGrid directly with the above parameters initialized from the cookie.
If you would have problem with creation the grid directly with the parameters which you need you can first create the grid with datatype: 'local' which will prevent the loading the grid. Then you change the parameters which you need and additionally set datatype to the value which you need ('json' or 'xml'). At the end you reload the grid. So the code should be like the following
$('#list').jqGrid('setGridParam', {
datatype: 'json',
sortname: "fName",
sortorder: "desc",
page: 2,
rowNum: 10
}).trigger('reloadGrid');
If you would have problem with creation the grid directly with the parameters which you need. additionally create the grid with datatype: 'local' it will prevent the loading the grid

jqGrid does not selects cell value as a selected dorp down value In edit mode

I am using jqGrid v 4.0 in my application to display tabuler data with Inline edit feature. One of the column in the Grid is a type of "Select". I have populated this select with following server side code:
//get all Departments
HRDept = $.ajax({
url: '../../PerformanceReview/GetHRDepartments/',
async: false,
success: function(data, result) {
if (!result)
alert('Failure to retrieve the HR Departments.');
}
}).responseText;
I have populated the Grid column with following sysntax:
name: 'HRDepartment', index: 'Department', align: 'left', editable: true, edittype: 'select', editoptions: {value: HRDept}
But on click of edit button (inline), it shows dropdown on on top of cell but the value is not equal to current cell value. it is always first value of drop down. I had compared the text which i am populating while loading Grid with the text of Dropdown and they are matching.
Could some one help me to set dropdown value similar as cell value.
Your edit options look wrong, it should be "value:text;" and the value should match your data results.
{ ... editoptions: {value: "HRDept:HR Department;" }}
You can checkout the demo of Row Edition -> Input Types at the jqGrid Demo site., which includes a dropdown list edit cell.
If you get the select values from the server you should use dataUrl option of the editoptions instead of value. Then the jqGrid will make the Ajax request at the beginning of the editing and fill the select element with the server response. It is important to understand that the server response should be in another form:
<select>
<option value='101 - Equity Partners'>101 - Equity Partners</option>
…
</select>
If you have already the code on the server which provide the information in another format and you can't change the server code you can define additional buildSelect function which get as the parameter the server response and should return the data in the above format ('...'). See UPDATED part of the answer for the code example.

jqGrid - how to add row to subgrid? or how to get primary key from parent row?

I am using ASP.MVC and jqgrid 3.7.2. The data loads OK into the grid and subgrid. Updating the master part of the table works great. I can update or remove a row from the subgrid since one of the fields in the subgrid is the primary key of the parent row. But when trying to add a row when the row is posted back to the server I am having trouble getting the parent row's Id. All the other subgrid values are posted as expected. I thought about trying to get the "selected" row of the parent, but the parent row is not selected, so I am not sure how to go about getting the parent rows Id (primary key) in master table thus will be a foreign key in the detail table. When there is any data is the subgrid, I can also get the parent's id since all my subgrid's rows have that as a hidden field. I noticed that during the post an Id field is part of the postback, but the value is null. Any ideas? I am using editing from the navigation bar.
i just figured a very lazy way of doing the same:
i used :
editurl:"datasource/notas_edit.php?pid="+row_id,
Then i get the value of it with $_GET in php ... lazy but works!
subGridRowExpanded: function (subgrid_id, row_id) {
var currentRow = $('#UtilitiesGrid').jqGrid('getRowData', row_id);
var utilityPrimaryKey = currentRow.UtilityId;
...
colNames: ['parentid','subid',...], //insert parentid column, hidden
colModel: [{name:"parentid", index:"parentid", hidden:true, editable:true,
editoptions: {
disabled:true, //dissabled in case colModel->hidden=false
value:utilityPrimaryKey , //Value for parentid in the add form
},
{name:"subid",index:"subid",key:true,hidden:true}
...
$("#"+subgrid_table_id).jqGrid('navGrid',"#"+pager_id,{
add:true,
del:true,
refresh:true,
refreshstate:"current",
search:false,
},
{},//edit options
//add options
{recreateForm:true //since clearAfterAdd is trueby default, recreate the form so we re-establish value for parent id
});
I ended up saving the primary key when the row was expanded. Then I used that value in the add options for the navgrid
subGridRowExpanded: function (subgrid_id, row_id) {
var currentRow = $('#UtilitiesGrid').jqGrid('getRowData', row_id);
var utilityPrimaryKey = currentRow.UtilityId`;
...
$("#" + subGridTableId).jqGrid('navGrid', "#" + pagerId, { edit: true, add: true, del: true, search: false, view: false, refresh: true },
...
{ // Add Options
reloadAfterSubmit: true,
afterSubmit: CheckForError,
closeAfterAdd: true,
url: "/Options/AddUtilityPwsId/" + utilityPrimaryKey
},

Resources