I'm currently using afterSaveCell
to handle manually updating some cells in a grid. I have this working fine if the user uses enter to save the currently editing cell.
Unfortunately, if they click or tab out of the cell they are editing directly into another cell I can no longer grab the cell value of the newly edited cell as getCell
will only return the html for the input control.
In summary, is there any way to access the value of the cell even while it is being edited?
jQuery(document).ready(function () {
var mydata = [
{id:"1", invdate:"2007-10-01",name:"test", note:"note", amount:"200.00",tax:"10.00",total:"210.00"},
{id:"2", invdate:"2007-10-02",name:"test2", note:"note2", amount:"300.00",tax:"20.00",total:"320.00"},
{id:"3", invdate:"2007-09-01",name:"test3", note:"note3", amount:"400.00",tax:"30.00",total:"430.00"},
{id:"4", invdate:"2007-10-04",name:"test", note:"note4", amount:"200.00",tax:"10.00",total:"210.00"},
{id:"5", invdate:"2007-10-05",name:"test5", note:"note5", amount:"300.00",tax:"20.00",total:"320.00"},
{id:"6", invdate:"2007-09-06",name:"test", note:"note6", amount:"400.00",tax:"30.00",total:"430.00"},
{id:"7", invdate:"2007-10-04",name:"test7", note:"note7", amount:"200.00",tax:"10.00",total:"210.00"},
{id:"8", invdate:"2007-10-03",name:"test8", note:"note8", amount:"300.00",tax:"20.00",total:"320.00"},
{id:"9", invdate:"2007-09-01",name:"test", note:"note9", amount:"400.00",tax:"30.00",total:"430.00"},
{id:"10",invdate:"2007-09-08",name:"test10",note:"note10",amount:"500.00",tax:"30.00",total:"530.00"},
{id:"11",invdate:"2007-09-08",name:"test11",note:"note11",amount:"500.00",tax:"30.00",total:"530.00"},
{id:"12",invdate:"",name:"TOTAL", note:"",amount:"",tax:"",total:""}
];
var grid = $("#list");
grid.jqGrid({
cellsubmit: 'remote',
cellurl: '/Example/GridSave',
datatype: "local",
data: mydata,
mtype: 'POST',
colNames: ['Inv No', 'Date', 'Client', 'Amount', 'Tax', 'Total', 'Notes'],
colModel: [
{ name: 'id', index: 'id', width: 65, sorttype: 'int', hidden: true },
{ name: 'invdate', index: 'invdate', width: 120, align: 'center', formatter: 'date', formatoptions: { newformat: 'd-M-Y' }, sortable: false },
{ name: 'name', index: 'name', editable: true, width: 90, sortable: false },
{ name: 'amount', index: 'amount', editable: true, width: 70, formatter: 'number', align: 'right', sortable: false },
{ name: 'tax', index: 'tax', editable: true, width: 60, formatter: 'number', align: 'right', sortable: false },
{ name: 'total', index: 'total', editable: true, width: 60, formatter: 'number', align: 'right', sortable: false },
{ name: 'note', index: 'note', width: 100, sortable: false }
],
rowNum: 1000,
pager: '#pager',
viewrecords: true,
sortorder: "desc",
caption: "afterSaveCell Issue",
height: "100%",
cellEdit: true,
gridComplete: function () {
calculateTotal();
},
afterSaveCell: function (rowid, name, val, iRow, iCol) {
calculateTotal();
}
});
});
function calculateTotal() {
var totalAmount = 0;
var totalTax = 0;
var grid = jQuery("#list");
var ids = grid.jqGrid('getDataIDs');
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
if (grid.jqGrid('getCell', id, 'name') === "TOTAL") {
grid.jqGrid('setRowData', id, {
'amount': totalAmount,
'tax': totalTax,
'total': totalAmount + totalTax
});
}
else {
totalAmount += Number(grid.jqGrid('getCell', id, 'amount'));
totalTax += Number(grid.jqGrid('getCell', id, 'tax'));
}
}
}
Thanks in advance!
I see two problems in your code. The first one is more cosmetic, but the correct solution can simplify many things in the future.
The first problem is that you add manual the "TOTAL" row as a part of grid data and calculate the values in the row inside calculateTotal
function. The better way is to use footerrow:true
option, which add additional row at the bottom of grid which will be not mixed with the grid data. For server based data you can use userdata
part of JSON or XML response from the server and use userDataOnFooter:true
additionally to till the data from the userData
jqGrid parameter to the footer row. In case of "local" datatype one can use footerData method to set (or get) the data in the footer. Additionally the method getCol can be used co calculate the sum of elements in the column. So your version of calculateTotal
function can be rewritten as
var grid = $("#list");
var calculateTotal = function() {
var totalAmount = grid.jqGrid('getCol','amount',false,'sum'),
totalTax = grid.jqGrid('getCol','tax',false,'sum');
grid.jqGrid('footerData','set',{name:'TOTAL',amount:totalAmount,tax:totalTax});
}
Now to your main problem. You use cell edit mode. If the function calculateTotal
(your original or my simplified version) will be called at the time when one from the cells of the 'amount' or 'tax' are in the editing mode, the calculateTotal
will be read HTML fragment with <input>
element instead of the string with the number and the calculation will failed.
I created the small demo which call calculateTotal
every second. So if you click on any cell from the
'amount' or 'tax' column you will see that in the footer row 0 will be displayed as the sum. So the demo having cellsubmit:'clientArray'
has the same problem as in your original code with cellsubmit:'remote'
.
To solve the problem one can use data
parameter of jqGrid during the sum calculation:
var grid = $("#list");
var calculateTotal = function() {
var gridData = grid.jqGrid('getGridParam','data'),
i=0,totalAmount=0,totalTax=0;
for (;i<gridData.length;i++) {
var rowData = gridData[i];
totalAmount += Number(rowData.amount);
totalTax += Number(rowData.tax);
}
grid.jqGrid('footerData','set',{name:'TOTAL',amount:totalAmount,tax:totalTax});
}
The corresponding fixed demo you will find here. In your final code you can remove
setInterval(calculateTotal, 1000);
which I used for demonstration purpose only and refresh the footer in the afterSaveCell
event handler only.
UPDATED: If you work with remote data you can not use data
parameter. So one have to get data from the <input>
element if needed. I created one more demo which demonstrate how one can do this. The code of calculateTotal
will be longer:
var getColumnIndexByName = function(grid,columnName) {
var cm = grid.jqGrid('getGridParam','colModel');
for (var i=0,l=cm.length; i<l; i++) {
if (cm[i].name===columnName) {
return i; // return the index
}
}
return -1;
},
getTextFromCell = function(cellNode) {
return cellNode.childNodes[0].nodeName === "INPUT"?
cellNode.childNodes[0].value:
cellNode.textContent || cellNode.innerText;
},
calculateTotal = function() {
var totalAmount = 0, totalTax = 0,
i=getColumnIndexByName(grid,'amount');
$("tbody > tr.jqgrow > td:nth-child("+(i+1)+")",grid[0]).each(function() {
totalAmount += Number(getTextFromCell(this));
});
i=getColumnIndexByName(grid,'tax');
$("tbody > tr.jqgrow > td:nth-child("+(i+1)+")",grid[0]).each(function() {
totalTax += Number(getTextFromCell(this));
});
grid.jqGrid('footerData','set',{name:'TOTAL',amount:totalAmount,tax:totalTax});
};
Thanks oleg the solution for me was applying and changing what you put
var ListTabla="ListFormatos";
var request="../../tabla_general/tabla_general_mantenimiento.php";
var getColumnIndexByName = function(grid,columnName) {
var cm = $("#"+grid).jqGrid('getGridParam','colModel');
for (var i=0,l=cm.length; i<l; i++) {
if (cm[i].name===columnName) {
return i; // return the index
}
}
return -1;
},
getTextFromCell = function(cellNode) {
return cellNode.childNodes[0].nodeName === "INPUT"?
cellNode.childNodes[0].value:
cellNode.textContent || cellNode.innerText;
},
calculateTotal = function(grid) {
total_hpr_suebas = retorna_suma('hpr_suebas',grid);
total_hpr_asifam = retorna_suma('hpr_asifam',grid);
total_hpr_bashpr = retorna_suma('hpr_bashpr',grid);
total_hpr_remcom = retorna_suma('hpr_remcom',grid);
total_hpr_basmes = retorna_suma('hpr_basmes',grid);
total_hpr_provcts = retorna_suma('hpr_provcts',grid);
total_hpr_provgrat = retorna_suma('hpr_provgrat',grid);
total_hpr_provvac=retorna_suma('hpr_provvac',grid);
$("#"+grid).jqGrid('footerData','set',{sec_detsec:'TOTAL',hpr_suebas:total_hpr_suebas,hpr_asifam:total_hpr_asifam,hpr_bashpr:total_hpr_bashpr,hpr_remcom:total_hpr_remcom,hpr_basmes:total_hpr_basmes,hpr_provcts:total_hpr_provcts,hpr_provgrat:total_hpr_provgrat,hpr_provvac:total_hpr_provvac});
};
retorna_suma=function(campo,grid)
{
total=0;
i=getColumnIndexByName(grid,campo);
$("tbody > tr.jqgrow > td:nth-child("+(i+1)+")",$("#"+grid)[0]).each(function() {
total+= Number(getTextFromCell(this));
});
return total;
}
function fn_jqgrid_history_provisiones_trabajador(tra_idtra,fecha_inicio,fecha_fin)
{
jQuery("#"+ListTabla).jqGrid({
url:request+"?action=search_history_provisiones_trabajador&tra_idtra="+tra_idtra+"&fecha_inicio="+fecha_inicio+"&fecha_fin="+fecha_fin,
async: false,
datatype: 'json',
colNames:['','ID','SECTOR','BASICO','ASIG. FAM','DIAS','BASE','REM. COMP.','BASE MES','P.CTS','P.GRAT.','P.VAC.','MES','ANIO','PORC.','SAL.VAC.','SAL.GRAT.'],
colModel:[
{name:'act', index:'act', width:50, resizable:true, align:"center",hidden:true},
{name:'id', index:'id', width:50, resizable:true, align:"center",hidden:true},
{name:'sec_detsec', index:'sec_detsec', width:80},
{name:'hpr_suebas', index:'hpr_suebas', width:60},
{name:'hpr_asifam', index:'hpr_asifam', width:50},
{name:'hpr_numdia', index:'hpr_numdia', width:30},
{name:'hpr_bashpr',index:'hpr_bashpr', width:60},
{name:'hpr_remcom,',index:'hpr_remcom', width:60},
{name:'hpr_basmes', index:'hpr_basmes', width:60},
{name:'hpr_provcts', index:'hpr_provcts', width:60},
{name:'hpr_provgrat', index:'hpr_provgrat', width:60},
{name:'hpr_provvac', index:'hpr_provvac', width:60},
{name:'hpr_meshpr', index:'hpr_meshpr', width:30},
{name:'hpr_aniohpr,',index:'hpr_aniohpr', width:30},
{name:'hpr_salpor', index:'hpr_salpor', width:50},
{name:'hpr_salval_vac', index:'hpr_salval_vac', width:50},
{name:'hpr_salval_grat', index:'hpr_salval_grat', width:50}
],
pager: '#paginacion',
rowNum:10,
rowList:[10,20,30],
sortname: 'ID',
ondblClickRow:function(rowid, iRow, iCol, e)
{
obj=jQuery("#"+ListTabla).jqGrid('getRowData',rowid);
}
,
sortorder: 'desc',
editurl:request,
viewrecords: true,
caption: 'Provisiones',
//rownumbers: true,
height: 250,
rowheight: 280,
footerrow : true,
gridComplete: function () {
calculateTotal(ListTabla);
},
afterSaveCell: function (rowid, name, val, iRow, iCol) {
//calculateTotal(ListTabla);
}
}).navGrid('#paginacion',{add:false,edit:false, del:false});
jQuery("#"+ListTabla).jqGrid('bindKeys', {"onEnter":function( rowid ) {
obj=jQuery("#"+ListTabla).jqGrid('getRowData',rowid);
} } );
}
If you just want to recalculate total number, you can use trigger to reload the grid in afterSaveCell event. Like this:
afterSaveCell: function (rowid, name, val, iRow, iCol)
{
jQuery("#list11").jqGrid('setGridParam',{datatype:'local',loadonce:true}).trigger('reloadGrid');
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With