I want to have delete functionality in my JQGrid for deleting multiple rows. My code looks like this:
{height:180,mtype:"POST",closeAfterDel:true, url:'gridedit.jsp',reloadAfterSubmit:true,
onclickSubmit: function (options, rowid) {
var rowData = jQuery(this).jqGrid('getRowData', rowid);
var params ={amount:rowData.amount,account:rowData.account.replace(/-/g,"")};
return params;
},
afterSubmit: function () {
$(this).jqGrid('setGridParam', {datatype:'json'});
return [true,''];
}
}
I want to make deletions as per the values of the column rowData.account
The problem is that when I select multiple rows, I can see that the grid passes all the rowid's back to the edit URL, but only passes the rowData.account value of the first row !
Is there a way to make the grid pass back all the values? I cant delete based on the row id on the back end as my database does not have any row id's.
Please help.
Here is my grid code:
jQuery(document).ready(function(){
jQuery("#list").jqGrid({
datatype: 'json',
url:'gridfeeder.jsp?ctlSelectedDate=<%= request.getParameter("ctlSelectedDate")%>',
colNames: ['Date', 'Account ', 'Amount', 'Code'],
colModel: [
//First Column, DATE
{name: 'adate', index: 'adate', width: 300, sorttype: 'date', align: 'center',datefmt: 'Y-m-d',
editable:true, formatter: myLinkFormatter, editoptions:{
dataInit:function(elem)
{
jQuery(elem).datepicker({
showButtonPanel: true,
changeMonth: true,
changeYear: true
});
}}, search:true, stype:'text',searchoptions:{
dataInit:function(elem)
{
jQuery(elem).datepicker({
showButtonPanel: true,
changeMonth: true,
changeYear: true
});
}
}
},
//Second Column, ACCOUNT
{ name: 'account', index: 'account', width: 300, align: 'center', sorttype: 'string', editable:true,
search:true, stype:'text',editrules:{custom:true, custom_func:
//Validation for this column for editing
function(value, colname) {
if (value.length<9 || value.length>11)
return [false,"Invalid Input"];
else
return [true,""];
}
},
searchrules:{custom:true, custom_func:
//Validation for this column for searching
function(val, colname) {
if (val.length<9 || val.length>11)
return [false,"Invalid Input"];
else
return [true,""];
}
}
},
//Third Column, AMOUNT
{ name: 'amount', index: 'amount', width: 300, align: 'center', sorttype: 'float', editable:true,
editrules:{number:true}, search:true, stype:'text'
},
//Fourth Column, CODE
{ name: 'code', index: 'code', width: 300, align: 'center', sorttype: 'float', editable:true,
search:true, stype:'text'
}
],
pager: "#pager", //Identifying the navigation bar
rowNum: 500, // how many rows to display on page 1
rowList: [500,1000, 2000, 3000,4000], //values for the dropdown which specifies how many rows to show
sortorder: "desc", //the order of sorting by default
viewrecords: true, // displays total number of rows
gridview: true,
autoencode: true,
height:400, //height of the grid
ignoreCase:true,// case insensitive search
multiselect:true, // checkboxes before each row
multiboxonly: true,
loadonce:true, //for client side sorting, searching and pagination
caption:"This is me" // caption for the grid header
here is the navgrid section :
}).navGrid('#pager',{edit:true,add:true,del:true,search:true,refresh:true},
// Options for EDIT
{height:280,mtype: "POST",closeAfterEdit: true,reloadAfterSubmit:true, url:'gridedit.jsp',
recreateForm: true,
//set some properties beofre the dialog box is seen by the user
beforeShowForm: function(form) {
/*$('#adate',form).attr('readonly','readonly');
$('#account',form).attr('readonly','readonly');*/
$('#adate',form).hide();
$('#account',form).hide();
},
// what happens when the user clicks submit. passing extra parameters
onclickSubmit: function (options, postdata) {
var rowid = postdata[this.id + "_id"]; // postdata.list_id
var dataF = jQuery('#list').jqGrid ('getCell', rowid, 'account');
return {account:dataF.replace(/-/g,"")};
},
// changing the datatype
afterSubmit: function () {
$(this).jqGrid("setGridParam", {datatype: 'json'});
return [true,''];
}
},
//ADD options
{height:280,mtype:"POST", closeAfterAdd:true, reloadAfterSubmit:true, url:'gridedit.jsp',
beforeShowForm: function(form) {
/*var cm = jQuery("#list").jqGrid('getColProp','adate');
alert(cm);
cm.editable = false;
$('#adate',form).attr('readonly','readonly');
$('#account',form).attr('readonly','readonly');*/
$('#adate',form).show();
$('#account',form).show();
},
//Change the datatype
afterSubmit: function () {
$(this).jqGrid("setGridParam", {datatype: 'json'});
return [true, ""];
}
},
{height:180,mtype:"POST",closeAfterDel:true, url:'gridedit.jsp',reloadAfterSubmit:true,
/* onclickSubmit: function (options, rowid) {
var rowData = jQuery(this).jqGrid('getRowData', rowid);
var params ={account:rowData.account.replace(/-/g,"")};
return params;
},*/
delData: {
account: function() {
var sel_id = $("#list").jqGrid('getGridParam', 'selrow');
var value = $("#list").jqGrid('getCell', sel_id, 'account');
return value.replace(/-/g,"");
}
},
afterSubmit: function () {
$(this).jqGrid('setGridParam', {datatype:'json'});
return [true,''];
}
}
);
function myLinkFormatter(cellvalue, options, rowObject) {
return "<a href='account094act.jsp?GETDATE=" + cellvalue + "&GETACC=" + rowObject[1] + "'>" + cellvalue + "</a>";
}
jQuery("#refresh_list").click(function(){
jQuery("#list").setGridParam({datatype: 'json'});
jQuery("#list").trigger("reloadGrid");
});
});
One uses mostly unique values which are the best for your situation as rowids. Probably you should consider to use the value from account column as rowid? You don't posted the full code of jqGrid which you you and don't posted JSON/XML data used for filling the grid. So it's difficult to give an exact advice to you.
You can consider to place key: true property in colModel in the definition of the column account. If all values from the column are unique (the values are different in all rows of the grid) then you can use the settings. In the case the rowid (the value of id attribute of <tr> elements of the grid) will be assigned the same as the values from account column.
All editing operation sends id of the editing row. So you will get account sent to the server. In case of multiselect: true jqGrid send comma separated list of rowids. In your case you will get on the server comma separated list of deleted accounts. Probably you can get all other information (like amount), if it's required, based on the account value. If account value are really unique and you have all data on the server that you can get any information which corresponds to account chosen.
Related
I'm using jqgrid 4.8.2. If a user clicks on a row, I want to save the previously selected row and display the current row in edit mode. I've used the code from previous answers but can't get this functionality to work. After some debugging and looking through the source code for jqgrid, it appears saveRow does not fire because the 'editable' attribute for the previous row is immediately set to 0. There is a clause in the jqgrid source code that looks for this attribute before saving the row:
editable = $(ind).attr("editable");
o.url = o.url || $t.p.editurl;
if (editable==="1") {....saveRow occurs...}
Any suggestion on how to work around this?
var editingRowId;
var myEditParam = {
keys: true,
extraparam: {activityID: aID},
oneditfunc: function (id) { editingRowId = id; },
afterrestorefunc: function (id) { editingRowId = undefined; },
aftersavefunc: function (id) { editingRowId = undefined; }
};
var myGrid = jQuery("#spend_grid").jqGrid({
url: parentGridURL,
mtype: "POST",
datatype: "json",
postData: {filters: myFilters},
gridview: false, //added for IE
altRows: true,
emptyrecords: 'NO PAYMENTS FOUND',
editurl: savePaymentURL,
onSelectRow: function (id) {
console.log('id=' + id + ' editingRowId =' + editingRowId);
var $this = $(this);
if (editingRowId !== id) {
if (editingRowId) {
// save or restore currently editing row
console.log('should be saving ' + editingRowId);
$this.jqGrid('saveRow', editingRowId, myEditParam);
console.log('done saving');
}
$this.jqGrid("editRow", id, myEditParam);
}
},
search: true,
sortname: lastSortName,
sortorder: lastSortOrder,
page: lastPage,
pager: jQuery('#report_pager'),
rowNum: lastRowNum,
rowList: [10,20,50,100],
viewrecords: true,
clearSearch: false,
caption: "Payments",
sortable: true,
shrinkToFit: false,
excel: true,
autowidth: true,
height: 300,
subGrid: true, // set the subGrid property to true to show expand buttons for each row
subGridRowExpanded: showChildGrid, // javascript function that will take care of showing the child grid
colModel: [
{ label: 'Payment ID',
name: 'PAYMENTID',
index: 'p.paymentID',
key: true, width: 75
},...// removed for brevity
{name : 'actions',
label: 'Actions',
index: 'formAction',
formatter:'actions',
width: 75,
search:false,
formatoptions: {
keys: true,
editbutton: false,
delOptions: { url: savePaymentURL }
}
}
]
}).inlineNav('#report_pager',
// the buttons to appear on the toolbar of the grid
{
restoreAfterSelect: false, // *****SOLUTION******
save:false,
edit: false,
add: false,
cancel: false
});
Found a solution to the issue. After examining the jqgrid source code I found that restoreAfterSelect: true is the default setting for the inlineNav. I added restoreAfterSelect: false and now the previous row saves.
I have 2 requirements I need to solve for. I'm using a JQGrid on an aspx page with other form controls. Saving the main form generates a database id that is populated in a hidden field. If the hidden field is empty, I don't want to save the grid record because I need the db id first. If the hidden field has a value, I want to save the row with a editurl.
The second part is related to a Bootstrap multiselect in one of the grid columns (I need the filtering capability). When a user selects a value from the multiselect I'd like to populate the PERNR column with the value selected. I can't use the onchange event for the multiselect since if the user doesn't change from the first option obviously it won't trigger the event.
How can I solve these 2 issues?
var roleDdlItems = $.parseJSON($("input[id$='hdfRoleDdlItems']").val());
$("#grdParticipants").jqGrid({
jsonReader: {
repeatitems: false,
root: 'Table',
page: function (obj) { return 1; },
total: function (obj) { return 2; },
records: function (obj) { return obj.ItemCount; },
id: "0"
},
caption: getParticipantCaption(),//"Participants",
pgbuttons: false,
recordtext: "Total: {2}",
emptyrecords: "",
loadtext: "Loading...",
pgtext: "",
datatype: function () {
UpdateParticipant("getParticipants");
},
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
// serializeGridData: function (postData) { return JSON.stringify(postData); },
colNames: ['Id', 'PERNR', 'Name', 'Email', 'RoleId', 'Role', 'Active', 'Updated'],
colModel: [
{ name: 'Id', index: 'Id', hidden: true, editable: true, hidedlg: true },
{ name: 'PERNR', index: 'PERNR', hidden: true, editable: true, hidedlg: true },
{ name: 'Name', index: 'Name', width: 200, align: "center", editable: true, edittype: "select",
editoptions: { value: function () {
var ITDdlItems = $.parseJSON($("input[id$='hdfITEmployeesDdlItems']").val());
var s = "";
if (ITDdlItems.Table4 && ITDdlItems.Table4.length) {
for (var i = 0, l = ITDdlItems.Table4.length; i < l; i++) {
var item = ITDdlItems.Table4[i];
s += item.PERNR + ":" + item.Name + ";";
}
}
s = s.substring(0, s.length - 1);
return s;
},
dataInit: function (e) {
$(e).multiselect({
maxHeight: 200,
enableFiltering: true,
filterPlaceholder: "Search Employees",
enableCaseInsensitiveFiltering: true,
templates: {
filter: '<li class="multiselect-item filter"><div class="input-group"><input class="form-control input-sm multiselect-search" id="txtITEmployeeFilter" type="text"></div></li>',
filterClearBtn: "<span class='input-group-btn'><button class='btn btn-default input-sm multiselect-clear-filter' type='button'><i class='glyphicon glyphicon-remove'></i></button><button class='btn btn-primary input-sm multiselect-clear-filter' type='button' onclick='javascript:searchEmployees("#" + e.id + "");'><i class='glyphicon glyphicon-search'></i></button></span>"
},
onDropdownHide: function (event) {
$(e).multiselect("updateButtonText");
$(e).multiselect("updateSelectAll");
}
// onChange: function(option, checked) {
// var selectedOption = $("#" + e.id + " option:selected").val();
// alert(selectedOption);
// }
});
}
}
},
{ name: 'Email', index: 'Email', width: 250, align: "center", editable: false },
{ name: 'RoleId', index: 'RoleId', hidden: true, editable: true, hidedlg: true },
{ name: 'Role', index: 'Role', width: 175, align: "center", editable: true, edittype: "select",
editoptions: { value: function () {
var roleDdlItems = $.parseJSON($("input[id$='hdfRoleDdlItems']").val());
var s = "";
if (roleDdlItems.Table3 && roleDdlItems.Table3.length) {
for (var i = 0, l = roleDdlItems.Table3.length; i < l; i++) {
var item = roleDdlItems.Table3[i];
s += item.Id + ":" + item.Role + ";";
}
}
s = s.substring(0, s.length - 1);
return s;
},
dataInit: function (e) {
$(e).multiselect({
maxHeight: 200,
onDropdownHide: function (event) {
$(e).multiselect("updateButtonText");
$(e).multiselect("updateSelectAll");
}
});
}
}
},
{
name: 'Active', index: 'Active', hidden: false, width: 75, align: "center", editable: true, hidedlg: true,
edittype: 'checkbox', editoptions: { value: "true:false", defaultValue: "Active" },
formatter: "checkbox", formatoptions: { disabled: true }
},
{ name: 'Updated', index: 'Updated', width: 100, align: "center", editable: false, sorttype: "date",
formatter: 'date', formatoptions: { newformat: 'n/j/y g:i A' }
}
],
rowNum: 5000,
autoWidth: true,
rowList: [],
pager: '#pgrParticipants',
toppager: true,
sortname: 'Name',
viewrecords: true,
sortorder: 'asc'
});
$('#grdParticipants').navGrid("#pgrParticipants", {edit: false, add: false, del: true, refresh: false, search: false, view: false});
$('#grdParticipants').inlineNav('#pgrParticipants',
// the buttons to appear on the toolbar of the grid
{
edit: true,
add: true,
del: true,
cancel: true,
editParams: {
keys: true
},
addParams: {
addRowParams: {
keys: true
}
}
});
$('#grdParticipants').navSeparatorAdd('#pgrParticipants', {
sepclass: 'ui-separator',
sepcontent: '',
position: 'last'
});
$('#grdParticipants').navButtonAdd('#pgrParticipants',
{
buttonicon: "ui-icon-help",
title: "Roles & Responsibilities Matrix",
caption: "Roles & Responsibilities Matrix",
position: "last",
onClickButton: showRoleMatrix
});
* EDIT *
The datatype function contains an ajax call that populates the grid. I’m using this based on an example someone else in my company provided. I’ll look around today for a better method, as it sounds this isn’t the best way. Maybe using url, which I stumbled across today.
This is a tab interface to track outages that will ultimately have a total of 5 separate JQGrids. When the page initially loads for a new outage this grid is on the first tab and is empty. It would only contain records if they’re editing an existing outage. In that instance, I would populate values in the main outage form controls and load data in the grid. The UpdateParticipant function seemed work well for this as it allows me to check for that hidden field before deciding whether a db call is even needed.
The PERNR is an employee id that the user doesn’t need to know, hence hidden. It’s not strictly confidential info, but we don’t advertise it either. They only need to see Name and Email (maybe) based on the value selected from the Name multiselect. Id will be a Participant Id generated by the database after the grid data is saved. Which can’t happen until the main outage form above is saved because I need that unique Outage Id as a foreign key for the participants. This attaches a participant to an outage and becomes the unique Id for the grid rows.
The selectedOption = $("#" + e.id + " option:selected").val() is commented out, but was only to trigger onchange for that specific Bootstrap Multiselect. The Role multiselect didn’t have an onchange function registered in code. So yes, it was for one element only. As mentioned previously, I was trying to use this to populate PERNR on a Name select. I need PERNR not Name to save to the db later. To solve for this I’m using the custom formatter on that column so I’ve since removed that onchange function for the Name multiselect. The ITDdlItems = $.parseJSON($("input[id$='hdfITEmployeesDdlItems']").val()) contains a json list of employee names and PERNRs to populate the Name multiselect. That works fine so this isn’t code relevant.
The only thing I need to figure out is how to perform a check for OutageId in the hidden field before the grid data is posted to the server. Thinking about it last night, if all else fails, I’ll let it post to the server and check there for the OutageId. I just don’t like posting if it isn’t going to make a db call. I’d share a demo somewhere if I knew how. This is an internal application so my options are limited.
I am using JQGrid with Multiselect filter to filter individual columns.
Currently I am populating filters(e.g. SkillCategory column) using database master values
{
name: 'SkillCategory', index: 'SkillCategory', width: '5%', sortable: true, resizable: true, stype: 'select',
searchoptions: {
clearSearch: false,
sopt: ['eq', 'ne'],
dataUrl: 'HttpHandler/DemandPropertyHandler.ashx?demprop=skillcat',
buildSelect: createSelectList,
attr: { multiple: 'multiple', size: 4 },
position: {
my: 'left top',
at: 'left bottom'
},
dataInit: dataInitMultiselect
}
},
This approach is populating all available master list(for SkillCategory) in to filter.
I would like to show only available filter value based on those are present in available rows for particular column(for SkillCategory).
This should show "Programming" and "Data" as option for SkillCategory filter as rows contains only "Programming" and "Data" value for that column.
I found below code(sorry forgot the link)
getUniqueNames = function (columnName) {
var texts = $("#listTableSupply").jqGrid('getCol', columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i = 0; i < textsLength; i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
}
buildSearchSelect = function (uniqueNames) {
var values = ":All";
$.each(uniqueNames, function () {
values += ";" + this + ":" + this;
});
return values;
}
setSearchSelect = function (columnName) {
$("#listTableSupply").jqGrid('setColProp', columnName,
{
searchoptions: {
sopt: ['eq', 'ne'],
value: buildSearchSelect(getUniqueNames(columnName)),
attr: { multiple: 'multiple', size: 3 },
dataInit: dataInitMultiselect
}
}
);
}
Calling setSearchSelect("SkillCategory")
.... caption: 'Supply',
emptyrecords: "No records to view",
loadtext: "Loading...",
refreshtext: "Refresh",
refreshtitle: "Reload Grid",
loadComplete: loadCompleteHandler1,
ondblClickRow: function (rowid) {
jQuery(this).jqGrid('viewGridRow', rowid);
},
beforeRequest: function () //loads the jqgrids state from before save
{
modifySearchingFilter.call(this, ',');
}
}).jqGrid('bindKeys');
$('#listTableSupply').bind('keydown', function (e) {
if (e.keyCode == 38 || e.keyCode == 40) e.preventDefault();
});
setSearchSelect("SkillCategory");
$('#listTableSupply').jqGrid('navGrid', '#pagerSupply', {
cloneToTop: true,
refresh: true, refreshtext: "Refresh", edit: false, add: false, del: false, search: false
}, {}, {}, {}, {
multipleSearch: true,
multipleGroup: true,
recreateFilter: true
}); .....
But seems its not working. Only "All" value is populated.
Any idea how can I achieve this.
Update1:
As per Oleg's suggestion below is the working code which worked for me.
initializeGridFilterValue = function () {
//jQuery("#listTableSupply").jqGrid('destroyGroupHeader');
setSearchSelect("SkillCategory");
jQuery("#listTableSupply").jqGrid("filterToolbar", {
stringResult: true,
searchOnEnter: true,
defaultSearch: myDefaultSearch,
beforeClear: function () {
$(this.grid.hDiv).find(".ui-search-toolbar .ui-search-input>select[multiple] option").each(function () {
this.selected = false; // unselect all options
});
$(this.grid.hDiv).find(".ui-search-toolbar button.ui-multiselect").each(function () {
$(this).prev("select[multiple]").multiselect("refresh");
}).css({
width: "98%",
marginTop: "1px",
marginBottom: "1px",
paddingTop: "3px"
});
}
});
jQuery("#listTableSupply").jqGrid('setGridHeight', 300);
}
And setting it from loadComplete event like below:
function loadCompleteHandler1() {
initializeGridFilterValue();
}
I see that you use the code from my old answer. About your problem: I suppose that you first call filterToolbar which creates the filter toolbar and only later you call setSearchSelect which set new searchoptions.value property. Another possible problem is that you call setSearchSelect before the data will be loaded in the grid. If you use datatype: "local" with data parameter then the data are filled in the grid during creating of the grid. If you use datatype: "json" then you should first load the data from the server and then call setSearchSelect and filterToolbar inside of loadComplete. For example if you use loadonce: true then you can test the value of datatype parameter inside of loadComplete. If the value is "json" then you made initial loading of the data. So you should call setSearchSelect, then if required call destroyFilterToolbar and finally call filterToolbar to create filter toolbar which selects will have all required values.
I have a multi-selected Jqgrid. Initially on loading the grid with the Json reponse from the server, the multiselected rows persist correctly as I navigate from one page to another.
The ids of the rows selected are stored in an Array and this Array is updated on paging. I use this array to check the already selected rows on returning back to the page. Sorting works fine and I faced no problem so far.
On applying a filter on a particular field, a request is sent to the server which returns the new filtered result in Json and then reloads the grid with it.
The first page is rendered correctly with the selected rows checked but on changing the page and returning back the rows are no longer selected. However the array still contains the ids and is also containing the new added ids.
How is that the Multiselected feature stops working after a reload??? Or is it not even because of the reload??
Here is the code:
<script type='text/javascript'>
var selectedFieldsMap={};
var selectedFieldsObjs = [];
var selectedFieldIds = [];
$(function() {
//function called when applying a filter
$('#ApplyFilterBtn').click(function() {
saveGridState();
$('#Grid').setGridParam({ url: getUrl() });
$('#Grid').trigger('reloadGrid');
});
});
function saveGridState() {
var selectedIds = $('#Grid').getGridParam('selarrrow');
$('#Grid').data(current_page, selectedIds);
_.each(selectedIds, function(id) {
selectedFieldIds.push(id);
});
var idsToBeAdded = _.difference(selectedIds, getExistingRowIdsForGrid('#list'));
selectedFieldsMap[current_page] = idsToBeAdded;
_.each(idsToBeAdded, function(id) {
selectedFieldsObjs.push($('#Grid').getRowData(id));
});
}
function getExistingRowIdsForGrid(gridSelector) {
var existingFields = $(gridSelector).getRowData();
return _.map(existingFields, function(obj) { return obj.Id; });
function resetFilterValuesAndReloadGrid() {
//reset filters and set grid param
$('#Grid').setGridParam({
sortname: 'Id',
sortorder: 'asc',
page: 1,
url: getUrl()
});
$('#Grid').jqGrid('sortGrid', 'Id', true);
$("#Grid").trigger('reloadGrid');
}
$("#Grid").jqGrid({
url: getUrl(),
datatype: "json",
edit: false,
add: false,
del: false,
height: 330,
mtype: 'GET',
colNames: ['Id', 'Type', 'Category'],
jsonReader: {
root: "DataRoot",
page: "CurrentPage",
total: "TotalPages",
records: "TotalRecords",
repeatitems: false,
cell: "",
id: "0"
},
colModel: [
{ name: 'Id', index: 'Id', width: 95, align: 'center', sorttype: "int" },
{ name: 'Type', index: 'ValueTypeName', width: 110, align: 'left',sortable: true },
{ name: 'Category', index: 'Category', width: 72, align: 'left', sortable: true },
],
pager: '#pager',
rowNum: pageCount[0],
rowList: pageCount,
sortname: 'Id',
sortorder: 'asc',
viewrecords: true,
gridview: true,
multiselect: true,
loadComplete: function () {
if(selectedFieldIds) {
$.each(_.uniq(selectedFieldIds), function(index, value) {
$('#Grid').setSelection(value, true);
});
}
} ,
onPaging : function () {
saveGridState();
},
loadBeforeSend: function() {
current_page = $(this).getGridParam('page').toString();
} ,
onSortCol: function () {
saveGridState();
}
});
}
function getUrl() {
//return url with the parameters and filtering
}
</script>
The problem is solved, what happens is on reload of the grid the function which checks the row is called as it is in the document.ready()and the on grid loadComplete the same function is called. Toggle happens and the selection is removed. I've added an if condition to see if the grid is selected or not.
loadComplete: function () {
var selRowIds = jQuery('#Grid').jqGrid('getGridParam', 'selarrrow');
if (selRowIds.length > 0) {
return false;
} else {
var $this = $(this), i, count;
for (i = 0, count = idsOfSelectedRows.length; i < count; i++) {
$this.jqGrid('setSelection', idsOfSelectedRows[i], false);
}
}
}
I have poured through every question asked on this website related to populating the jqGrid summary footer WITHOUT the userdata being a server request. And the jqGrid wiki resource and just cannot find an answer. Is this possible to do?
I use the jqGrid in many typical ways as part of my admin portal but have one particular use where I want the look & feel of the jqGrid to start out as an empty UI container of sorts for some user interaction adding rows through a form which doesn't post on Submit (thanks to Oleg's great script below) but simply adds the row and updates the summary footer with the values from the newly added row. I have 'summarytype:"sum"' in the colModel, "grouping:true", footerrow: true, userDataOnFooter: true, altRows: true, in the grid options but apart from the initial values supplied by the userdata in the local data string, the summary footer values never change. It seems like no one wants to touch this subject. Is it because the primary nature of the jqGrid is it's database driven functionality? I use about 15 instances of the jqGrid in it's database driven stance (many of which are in a production service now) but need to use it for consistency sake (all my UI's are inside jqTabs) initially as a client side UI with no server request (everything will be saved later to db) but I am pulling my hair out trying to manipulate the summary footer programmatically on and by the client only. Can anyone suggest how to cause values to the summary footer to update when a new row is added the values of which would be summed up with any existing rows and which does not involve any posting to server, just updates inside the grid?
The code supplied is kind of long and based primarily on user Oleg's solution for adding a row from a modal form without posting to the server. I've changed the local array data to JSON string simply to better understand the notation as I'm used to xml. The jsonstring initializes the grid with one default row for the user to edit. I've left out the jsonReader because the grid would not render with it.
In a nutshell then what I want to do is to have the summary footer update when a new row is added to the grid (no posting to server occurring at this point) or edited or deleted. When a certain set of values is achieved the user is prompted by a displayed button to save row data to db.
var lastSel, mydata = { "total": 1, "page": 1, "records": 1, "rows": [{ "id": acmid, "cell": ["0.00", "0.00", "0.00", "0.00"]}], "userdata":{ "mf": 0.00, "af":0.00,"pf":0.00,"cf":0.00 }}
grid = $("#ta_form_d"),
onclickSubmitLocal = function (options, postdata) {
var grid_p = grid[0].p,
idname = grid_p.prmNames.id,
grid_id = grid[0].id,
id_in_postdata = grid_id + "_id",
rowid = postdata[id_in_postdata],
addMode = rowid === "_empty",
oldValueOfSortColumn;
// postdata has row id property with another name. we fix it:
if (addMode) {
// generate new id
var new_id = grid_p.records + 1;
while ($("#" + new_id).length !== 0) {
new_id++;
}
postdata[idname] = String(new_id);
//alert(postdata[idname]);
} else if (typeof (postdata[idname]) === "undefined") {
// set id property only if the property not exist
postdata[idname] = rowid;
}
delete postdata[id_in_postdata];
// prepare postdata for tree grid
if (grid_p.treeGrid === true) {
if (addMode) {
var tr_par_id = grid_p.treeGridModel === 'adjacency' ? grid_p.treeReader.parent_id_field : 'parent_id';
postdata[tr_par_id] = grid_p.selrow;
}
$.each(grid_p.treeReader, function (i) {
if (postdata.hasOwnProperty(this)) {
delete postdata[this];
}
});
}
// decode data if there encoded with autoencode
if (grid_p.autoencode) {
$.each(postdata, function (n, v) {
postdata[n] = $.jgrid.htmlDecode(v); // TODO: some columns could be skipped
});
}
// save old value from the sorted column
oldValueOfSortColumn = grid_p.sortname === "" ? undefined : grid.jqGrid('getCell', rowid, grid_p.sortname);
//alert(oldValueOfSortColumn);
// save the data in the grid
if (grid_p.treeGrid === true) {
if (addMode) {
grid.jqGrid("addChildNode", rowid, grid_p.selrow, postdata);
} else {
grid.jqGrid("setTreeRow", rowid, postdata);
}
} else {
if (addMode) {
grid.jqGrid("addRowData", rowid, postdata, options.addedrow);
} else {
grid.jqGrid("setRowData", rowid, postdata);
}
}
if ((addMode && options.closeAfterAdd) || (!addMode && options.closeAfterEdit)) {
// close the edit/add dialog
$.jgrid.hideModal("#editmod" + grid_id,
{ gb: "#gbox_" + grid_id, jqm: options.jqModal, onClose: options.onClose });
}
if (postdata[grid_p.sortname] !== oldValueOfSortColumn) {
// if the data are changed in the column by which are currently sorted
// we need resort the grid
setTimeout(function () {
grid.trigger("reloadGrid", [{ current: true}]);
}, 100);
}
// !!! the most important step: skip ajax request to the server
this.processing = true;
return {};
},
editSettings = {
//recreateForm:true,
jqModal: false,
reloadAfterSubmit: false,
closeOnEscape: true,
savekey: [true, 13],
closeAfterEdit: true,
onclickSubmit: onclickSubmitLocal
},
addSettings = {
//recreateForm:true,
jqModal: false,
reloadAfterSubmit: false,
savekey: [true, 13],
closeOnEscape: true,
closeAfterAdd: true,
onclickSubmit: onclickSubmitLocal
},
delSettings = {
// because I use "local" data I don't want to send the changes to the server
// so I use "processing:true" setting and delete the row manually in onclickSubmit
onclickSubmit: function (options, rowid) {
var grid_id = grid[0].id,
grid_p = grid[0].p,
newPage = grid[0].p.page;
// delete the row
grid.delRowData(rowid);
$.jgrid.hideModal("#delmod" + grid_id,
{ gb: "#gbox_" + grid_id, jqm: options.jqModal, onClose: options.onClose });
if (grid_p.lastpage > 1) {// on the multipage grid reload the grid
if (grid_p.reccount === 0 && newPage === grid_p.lastpage) {
// if after deliting there are no rows on the current page
// which is the last page of the grid
newPage--; // go to the previous page
}
// reload grid to make the row from the next page visable.
grid.trigger("reloadGrid", [{ page: newPage}]);
}
return true;
},
processing: true
}; //,
/*initDateEdit = function (elem) {
setTimeout(function () {
$(elem).datepicker({
dateFormat: 'dd-M-yy',
autoSize: true,
showOn: 'button', // it dosn't work in searching dialog
changeYear: true,
changeMonth: true,
showButtonPanel: true,
showWeek: true
});
//$(elem).focus();
}, 100);
},
initDateSearch = function (elem) {
setTimeout(function () {
$(elem).datepicker({
dateFormat: 'dd-M-yy',
autoSize: true,
//showOn: 'button', // it dosn't work in searching dialog
changeYear: true,
changeMonth: true,
showButtonPanel: true,
showWeek: true
});
//$(elem).focus();
}, 100);
};*/
//jQuery("#ta_form_d").jqGrid({
grid.jqGrid({
// url:'/admin/tg_cma/ta_allocations.asp?acmid=' + acmid + '&mid=' + merchantid + '&approval_code=' + approval_code,
//datatype: "local",
//data: mydata,
datatype: 'jsonstring',
datastr: mydata,
colNames: ['ID', 'Monthly Fees', 'ATM Fees', 'POS Fees', 'Card to Card Fees'],
colModel: [
{ name: 'id', index: 'id', width: 90, align: "center", editable: true, editoptions: { size: 25 }, formoptions: { rowpos: 1, colpos: 1, label: "EzyAccount ID", elmprefix: "(*) " }, editrules: { required: true} },
{ name: 'mf', index: 'mf', width: 130, align: "right", formatter: 'number', editable: true, summaryType: 'sum', editoptions: { size: 25 }, formoptions: { rowpos: 2, colpos: 1, label: "Monthly Fee", elmprefix: "(*) " }, editrules: { required: true} },
{ name: 'af', index: 'af', width: 130, align: "right", formatter: 'number', editable: true, summaryType: 'sum', editoptions: { size: 25 }, formoptions: { rowpos: 3, colpos: 1, label: "ATM Fee", elmprefix: "(*) " }, editrules: { required: true} },
{ name: 'pf', index: 'pf', width: 130, align: "right", formatter: 'number', editable: true, summaryType: 'sum', editoptions: { size: 25 }, formoptions: { rowpos: 4, colpos: 1, label: "POS Fee", elmprefix: "(*) " }, editrules: { required: true} },
{ name: 'cf', index: 'cf', width: 130, align: "right", formatter: 'number', editable: true, summaryType: 'sum', editoptions: { size: 25 }, formoptions: { rowpos: 5, colpos: 1, label: "Card to Card Fee", elmprefix: "(*) " }, editrules: { required: true} }
],
rowNum: 5,
rowList: [5, 10, 20],
pager: '#pta_form_d',
toolbar: [true, "top"],
width: 500,
height: 100,
editurl: 'clientArray',
sortname: 'id',
viewrecords: true,
sortorder: "asc",
multiselect: false,
cellEdit: false,
caption: "Allocations",
grouping: true,
/*groupingView: {
groupField: ['id', 'mf', 'af', 'pf', 'cf'],
groupColumnShow: [true],
groupText: ['<b>{0}</b>'],
groupCollapse: false,
groupOrder: ['asc'],
groupSummary: [true],
groupDataSorted: true
},*/
footerrow: true,
userDataOnFooter: true,
altRows: true,
ondblClickRow: function (rowid, ri, ci) {
var p = grid[0].p;
if (p.selrow !== rowid) {
// prevent the row from be unselected on double-click
// the implementation is for "multiselect:false" which we use,
// but one can easy modify the code for "multiselect:true"
grid.jqGrid('setSelection', rowid);
}
grid.jqGrid('editGridRow', rowid, editSettings);
},
onSelectRow: function (id) {
if (id && id !== lastSel) {
// cancel editing of the previous selected row if it was in editing state.
// jqGrid hold intern savedRow array inside of jqGrid object,
// so it is safe to call restoreRow method with any id parameter
// if jqGrid not in editing state
if (typeof lastSel !== "undefined") {
grid.jqGrid('restoreRow', lastSel);
}
lastSel = id;
}
},
afterEditCell: function (rowid, cellname, value, iRow, iCol) {
alert(iCol);
},
gridComplete: function () {
},
loadComplete: function (data) {
}
})
.jqGrid('navGrid', '#pta_form_d', {}, editSettings, addSettings, delSettings,
{ multipleSearch: true, overlay: false,
onClose: function (form) {
// if we close the search dialog during the datapicker are opened
// the datepicker will stay opened. To fix this we have to hide
// the div used by datepicker
//$("div#ui-datepicker-div.ui-datepicker").hide();
}
});
$("#t_ta_form_d").append("<input type='button' class='add' value='Add New Allocation' style='height:20px; color:green; font-size:11px;' />");
$("input.add", "#t_ta_form_d").click(function () {
jQuery("#ta_form_d").jqGrid('editGridRow', "new", {
//recreateForm:true,
jqModal: false,
reloadAfterSubmit: false,
savekey: [true, 13],
closeOnEscape: true,
closeAfterAdd: true,
onclickSubmit: onclickSubmitLocal
})
})
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.
Look at the answer for more information. I hope it will solve your problem.