I adopted the code from this post and made this fiddle. Try clicking the first row, then shift-clicking the last row. If you notice this code does very well, except the last row, the row that you click on, does not get selected. I have been scratching my head on this one. Can anyone help me alter the code so that the multiselect selects the last row too?
Thanks!
try replacing this: if ((shouldSelectRow = id == startID || shouldSelectRow)) {
with this:
if ((shouldSelectRow = id == startID || shouldSelectRow) && (id != rowid)){
I agree with Michael Gendin that you should not select the row with the id equal to rowid
. It's your main error. Nevertheless I would rewrite the most code of the demo to use rowIndex of DOM elements of the rows instead of enumerating of all rows of the grid. Additionally the selection of the text in IE is uncomfortable in your current code, so I would suggest removing it. The modified demo which you find here I used the following code of beforeSelectRow
callback:
beforeSelectRow: function (rowid, e) {
var $this = $(this), rows = this.rows,
// get id of the previous selected row
startId = $this.jqGrid('getGridParam', 'selrow'),
startRow, endRow, iStart, iEnd, i, rowidIndex;
if (!e.ctrlKey && !e.shiftKey) {
$this.jqGrid('resetSelection');
} else if (startId && e.shiftKey) {
$this.jqGrid('resetSelection');
// get DOM elements of the previous selected and the currect selected rows
startRow = rows.namedItem(startId);
endRow = rows.namedItem(rowid);
if (startRow && endRow) {
// get min and max from the indexes of the previous selected
// and the currect selected rows
iStart = Math.min(startRow.rowIndex, endRow.rowIndex);
rowidIndex = endRow.rowIndex;
iEnd = Math.max(startRow.rowIndex, rowidIndex);
for (i = iStart; i <= iEnd; i++) {
// the row with rowid will be selected by jqGrid, so:
if (i != rowidIndex) {
$this.jqGrid('setSelection', rows[i].id, false);
}
}
}
// clear text selection
if(document.selection && document.selection.empty) {
document.selection.empty();
} else if(window.getSelection) {
window.getSelection().removeAllRanges();
}
}
return true;
}
Add $('#grid').disableSelection();
to remove the annoying text selection
As discussed in Oleg's answer, here is an adjusted beforeSelectRow that does appended selections.
In my case, our users are selecting a bunch of rows for export, so additional selections does not usually mean they want to start a new selection.
beforeSelectRow: function(rowid, e) {
var $this = $(this), rows = this.rows,
// get id of the previous selected row
startId = $this.jqGrid('getGridParam', 'selrow'),
startRow, endRow, iStart, iEnd, i, rowidIndex;
if (!e.ctrlKey && !e.shiftKey) {
//intentionally left here to show differences with
//Oleg's solution. Just have normal behavior instead.
//$this.jqGrid('resetSelection');
} else if (startId && e.shiftKey) {
//Do not clear existing selections
//$this.jqGrid('resetSelection');
// get DOM elements of the previous selected and
// the currect selected rows
startRow = rows.namedItem(startId);
endRow = rows.namedItem(rowid);
if (startRow && endRow) {
// get min and max from the indexes of the previous selected
// and the currect selected rows
iStart = Math.min(startRow.rowIndex, endRow.rowIndex);
rowidIndex = endRow.rowIndex;
iEnd = Math.max(startRow.rowIndex, rowidIndex);
// get the rowids of selected rows
var selected = $this.jqGrid('getGridParam','selarrrow');
for (i = iStart; i <= iEnd; i++) {
// if this row isn't selected, then toggle it.
// jqgrid will select the clicked on row, so just ingore it.
// note that we still go <= iEnd because we don't know which is start or end.
if(selected.indexOf(rows[i].id) < 0 && i != rowidIndex) {
// true is to trigger onSelectRow event, which you may not need
$this.jqGrid('setSelection', rows[i].id, true);
}
}
}
// clear text selection (needed in IE)
if(document.selection && document.selection.empty) {
document.selection.empty();
} else if(window.getSelection) {
window.getSelection().removeAllRanges();
}
}
return true;
}
The solution of Oleg is not working in all selection mode (up/down). Thanks to him for the partial solution.
I correct this with this code:
You need 2 variables for stored the current start row Id and end row Id. And an other one to store the side of the selection.
var _currentStartSelectRow, _currentEndSelectRow, _isSideDown = null;
Code call by the beforeSelectRow callback:
beforeSelectRow: function (rowid, e) {
var $this = $(this), rows = this.rows,
// get id of the previous selected row
previousId = $this.jqGrid('getGridParam', 'selrow'),
previousRow, currentRow;
if (!e.ctrlKey && !e.shiftKey) {
_isSideDown = null;
$this.jqGrid('resetSelection');
} else if (previousId && e.shiftKey) {
$this.jqGrid('resetSelection');
// get DOM elements of the previous selected and the currect selected rows
previousRow = rows.namedItem(previousId);
currentRow = rows.namedItem(rowid);
if (previousRow && currentRow) {
//Increment
if (previousRow.rowIndex < currentRow.rowIndex) {
if (_isSideDown == false || _isSideDown == null) {
_currentStartSelectRow = previousRow.rowIndex;
_currentEndSelectRow = currentRow.rowIndex;
}
else {
_currentEndSelectRow = currentRow.rowIndex;
}
_isSideDown = true;
}
//Decrement
else {
if (_isSideDown == null) {
_currentStartSelectRow = currentRow.rowIndex;
_currentEndSelectRow = previousRow.rowIndex;
_isSideDown = false;
}
else if (_isSideDown == true) {
if (currentRow.rowIndex < _currentStartSelectRow) {
_currentStartSelectRow = currentRow.rowIndex;
_isSideDown = false;
}
else {
_currentEndSelectRow = currentRow.rowIndex;
}
}
else {
_currentStartSelectRow = currentRow.rowIndex;
}
}
for (i = _currentStartSelectRow; i <= _currentEndSelectRow; i++) {
// the row with rowid will be selected by jqGrid, so we don't need to select him:
if (i != currentRow.rowIndex) {
$this.jqGrid('setSelection', rows[i].id, false);
}
}
}
}
return true;
},
来源:https://stackoverflow.com/questions/11174499/shift-click-jqgrid-multiselect-missing-last-row