Reputation: 1243
I had a previous question regarding having buttons available in each row of a jqGrid, that would activate when the row was selected. With help from @Oleg
I was able to get it to work like I thought it should.
In further testing however, I have identified undesired behavior in that onSelectRow
event. What I found was that if I have a grid with 3 rows in it, and I click on row 2 (which activates the buttons), then (without clicking on the row 2 buttons) click on row 3 (which deactivates row 2 buttons & activates row 3 buttons), and change my mind again & click row 1 or 2 (doesn't matter), and at THAT point then click the "Re-Send"
(submit) button, what happens is that the selected row is then re-sent 3 separate times.
Following are the timestamps from 4 rows that were written from 1 "Re-Send" click yesterday.
2013-05-28 16:49:04.817
2013-05-28 16:49:04.653
2013-05-28 16:49:04.560
2013-05-28 16:49:04.467
I put some logging in the page & confirmed that it does call the POST 4 separate times, once for each click on a row in the grid.
The following sections contain most of the configuration/settings I currently have where the jqGrid gets built.
colNames: ["Destination", "Message Text", "Send Time","Message Action"],
colModel:[
{name:"Destination",index:"Destination",width:col1width,align:"left", xmlmap:"Rowset>Row>Destination",sortable:false},
{name:"MessageText",index:"MessageText",width:col2width,align:"left",xmlmap:"Rowset>Row>MessageText",sortable:false},
{name:"SendTime",index:"SendTime",width:col3width,align:"center",formatter:"date",formatoptions: {"srcformat":"ISO8601Long", "newformat":"Y-m-d H:i:s"},xmlmap:"Rowset>Row>SendTime",sortable:false},
{name: "msgAct",
width: col4width,
align: "center",
formatter: function() {
return "<input name='resendMsg' style='height:25px;width:65px;' type='submit' value='Re-Send' disabled='disabled' />" +
"<input name='cancelMsg' style='height:25px;width:55px;' type='submit' value='Cancel' disabled='disabled' />"
}}
],
viewrecords: true,
caption: capMsg,
rownum: 0,
height: "100%",
width: gridwidth,
toolbar: [true, "top"],
pager: jQuery("#pager1"),
sortname: "SendTime",
hidegrid: false, // hides the ability to collapse grid
defaults: {
altrows: true,
recordtext: "View {0} - {1} of {2}",
emptyrecords: "No records to view",
loadonce: true,
pgtext: "Page {0} of {1}"
},
Following is the onSelectRow
event.
onSelectRow: function(id) {
var tr = $(this).jqGrid("getInd",id,true);
var gridRow = $(this).jqGrid("getRowData",id);
var srow = $(this).jqGrid("getGridParam","selrow");
// disable all resendMsg & cancelMsg buttons in the grid
$(this).find("input[name=resendMsg]").attr("disabled","disabled");
$(this).find("input[name=cancelMsg]").attr("disabled", "disabled");
// now enable the buttons for the current row only
$(tr).find("input[name=resendMsg]").removeAttr("disabled");
$(tr).find("input[name=cancelMsg]").removeAttr("disabled");
// disable dropdowns & sendMsg submit button
// catch the Cancel button click
$(tr).find("input[name=cancelMsg]").click(function() {
// disable all resendMsg & cancelMsg buttons in the grid
$(this).find("input[name=resendMsg]").attr("disabled","disabled");
$(this).find("input[name=cancelMsg]").attr("disabled", "disabled");
// enable the dropdowns & clear the selection, reload grid
ReloadGrid();
});
// catch the Re-Send button click
$(tr).find("input[name=resendMsg]").click(function() {
ReSendMessage(gridRow.Destination, gridRow.MessageText);
// disable all resendMsg & cancelMsg buttons in the grid
$(this).find("input[name=resendMsg]").attr("disabled","disabled");
$(this).find("input[name=cancelMsg]").attr("disabled", "disabled");
// enable the dropdowns, clear the selection and exit
$("#myGrid").jqGrid("resetSelection");
});
},
and the remainder of the jqGrid code:
gridview: true,
xmlReader: {
root: "Rowsets",
row: "Row",
repeatitems: false,
id: "SendTime"
},
loadComplete: function() {
// increase row height
$("td",".jqgrow").height(40); // data grid rows
// alternate background of every other row
$("tr.jqgrow:odd").css({"background-color": "#DDDDDC", "background-image": "none"});
$("th.ui-th-column").css("font-weight","bold");
}
});
It's like the onSelectRow event is accumulating the number of clicks & then calling the click event's functions however many times a row was selected but a button wasn't clicked.
I have tested though, that if I click on a row, and then click on either of the submit buttons, that it processes as expected (a "Re-Send
" submits the row 1 time, and a "Cancel
" clears the selection & does nothing else).
I don't know if it is possible, but can you prevent a subsequent onSelectRow
from firing if a row's already selected? Can you clear the previous selection (or reset it) to prevent the onSelectRow
(and the click event for the button) from firing multiple times?
I'd appreciate any thoughts, comments or suggestions as to how to fix this behavior.
EDIT
Including the code for beforeSelectRow
as noted in a response below.
$("#myGrid").bind("jqGridBeforeSelectRow", function(e, id, eventOriginal) {
var gsr = $("#myGrid").jqGrid("getGridParam","selrow");
console.log(" **** beforeSelectRow - (before if) lastSel = " + lastSel + " id = " + id + " gsr = " + gsr);
if (id && id !== lastSel) {
console.log("id && id !== lastSel");
console.log(" id = " + id + " lastSel = " + lastSel);
};
if (id !== lastSel) {
if (lastSel == -1) { // first time thru
lastSel = id;
console.log(" **** beforeSelectRow - first time thru - new val = " + lastSel + " gsr = " + gsr);
return true;
}
else {
console.log(" **** beforeSelectRow - lastSel - " + lastSel + " <> id = " +id + " gsr = " + gsr);
return false;
}
}
else {
console.log(" **** beforeSelectRow - otherwise they matched - lastSel = " + lastSel + " id = " + id + " gsr = " + gsr);
return true;
}
});
After moving the .click
event from the onSelectRow
into the loadComplete
(for the Cancel button as a test), I tried the above code both inside & outside the code for the grid. It performs the same either way.
The issue is that the Cancel
button is supposed to reset the selection $("#myGrid").resetSelection();
and reload the grid. The code executes & doesn't give an error, but the very next time beforeSelectRow
fires (when the grid is reloaded), the id is still the same as it was when beforeSelectRow
and onSelectRow
fired when I clicked on the row, which means that I can never select a new row until the entire page is reloaded. Only on page load is when beforeSelectRow
doesn't fire.
EDIT
Following is the code for the Cancel button, which is now located inside the loadComplete
event.
// catch the Cancel button click
$(this).find("input[name=cancelMsg]").click(function() {
// disable all resendMsg & cancelMsg buttons in the grid
$(this).find("input[name=resendMsg]").attr("disabled","disabled");
$(this).find("input[name=cancelMsg]").attr("disabled", "disabled");
// enable the dropdowns & clear the selection, reload grid
console.log("ReloadGrid (inside Cancel function) ");
lastSel = -1;
$("#myGrid").trigger("reloadGrid");
Upvotes: 1
Views: 12459
Reputation: 221997
It's wrong to bind button (to use .click
) inside of onSelectRow
callback.
Instead of you can move the code with registering click
event handler inside of loadComplete
. You can just move the code from onSelectRow
to loadComplete
and replace $(tr)
to $(this)
to search inside of all buttons of the grid and not only the buttons of selected row. You can still set or remove disabled
attribute inside of onSelectRow
callback.
More better would be to make no individual binding for every button. One can just use onCellSelect
or beforeSelectRow
which will be called from click
handler bound on whole grid. See the answer and this one for code examples.
UPDATED: I am not sure that I understand correctly your problem, but I hope that the demo will demonstrate the solution of the problem. I don't used any explicit click
handler. The most important change (which could important if you use Internet Explorer) is adding class='cbox'
to the formatter to prevent return
in the line of jqGrid code. The most important part of the code is below
colModel: [
{ name: "text", width: 500 },
{ name: "msgAct", width: 150,
formatter: function () {
return "<input name='resendMsg' class='cbox' style='height:25px;width:65px;' type='submit' value='Re-Send' disabled='disabled'/>" +
"<input name='cancelMsg' class='cbox' style='height:25px;width:55px;' type='submit' value='Cancel' disabled='disabled'/>"
}}
],
onSelectRow: function (rowid) {
var tr = $(this).jqGrid("getInd", rowid, true);
$(this).find("input[name=resendMsg],input[name=cancelMsg]").attr("disabled", "disabled");
$(tr).find("input[name=resendMsg],input[name=cancelMsg]").removeAttr("disabled");
},
beforeSelectRow: function (rowid, e) {
var $self = $(this),
$td = $(e.target).closest("td"),
iCol = $.jgrid.getCellIndex($td[0]),
name = $(e.target).attr("name");
if (this.p.colModel[iCol].name === "msgAct") {
if (name === "resendMsg") {
alert("'Re-Send' button clicked in the row with id=" + rowid +
"\ntext in the row =\"" + $self.jqGrid("getCell", rowid, "text") + "\"");
} else if (name === "cancelMsg") {
alert("'Cancel' button clicked in the row with id=" + rowid);
setTimeout(function () {
$self.trigger("reloadGrid");
}, 50);
}
}
return true;
}
You can replace alerts inside of beforeSelectRow
to the action which you need.
Upvotes: 2