jqGrid afterclickPgButtons skip the line where isLeaf non is TRUE? - jqgrid

I use jqGrid 4.9.3-pre - free jqGrid by Oleg.
I use:
contextmenu
treegrid
form Edit
multiselect: false
Code
treeGrid:true,
ExpandColumn:'name',
treedatatype:"json",
treeGridModel:"adjacency",
treeReader:{
level_field: "level",
parent_id_field: "parent",
leaf_field: "isLeaf",
expanded_field: "expanded",
loaded:true,
},
loadonce: false
How to If isLeaf is TRUE skip the line and go to the next line where isLeaf non is TRUE?

Navigation buttons of Edit form have no special interface which could allow to skip some rows, but one can use onclickPgButtons to prevent the navigation to the next/previous row and to simulate the click on the same button immediately after that. It's important to understand that jqGrid contains hidden field in the form with the id="id_g", which will be used by form editing as the rowid of the current editing row. Thus one can change the value of the hidden field before simulation of the click.
The corresponding implementation of the onclickPgButtons callback could be the following:
onclickPgButtons: function (buttonName, $form, rowid) {
var $self = $(this),
iRow = $self.jqGrid("getGridRowById", rowid).rowIndex,
isLeaf = $self.jqGrid("getGridParam", "treeReader").leaf_field,
rows = this.rows,
nRows = rows.length,
iInc = buttonName === "next" ? 1 : -1,
isNextRowVisibleLeaf = function () { // iRow - the current row
var $nextRow = $(rows[iRow + iInc]),
rowidNext = $nextRow.attr("id");
if (rowidNext != null) {
var nextItem = $self.jqGrid("getLocalRow", rowidNext);
if (nextItem != null && nextItem[isLeaf] && $nextRow.css("display") !== "none") {
return true;
}
}
return false;
},
$button = $(buttonName === "next" ? "#nData" : "#pData");
if (isNextRowVisibleLeaf()) {
return true; // nothing to do
}
// we need to fix the row, which the next row is visible leaf
while (iRow < nRows && iRow > 0) {
iRow += iInc;
if (isNextRowVisibleLeaf()) {
// set the value of hidden field of the form
// to the id of the found row and simulate the click
// on the same navigation button
$form.find("#id_g").val($(rows[iRow]).attr("id"));
setTimeout(function () {
$button.click();
}, 50);
return false;
}
}
return false;
}
See the demo.

Related

Handsontable - Unable to keep html element created by a custom renderer visible

I am using the open source version of handsontable (version 0.29.2). I created a custom renderer that creates a hidden SPAN element/icon on every row. When input fails validation, I use jQuery to programmatically unhide/show the SPAN tag/icon so that it appears in the right-hand side of the cell. It works great, but unfortunately when I enter an invalid value into another cell, the icon from the first cell disappears. The preferred behavior is to have all of the icons visible in cells where a validation issue exists.
Question: Is there a way to keep all of the icons visible?
If this is not possible, is there a different way in handsontable to display an image after validation? As you can see from the code below (and my jsfiddle example), I am not using the built-in handsontable validation hooks. With the built-in validation, I can't add an icon like I want - I can only override the default style of an invalid cell by using invalidCellClassName.
I have created a simple example with instructions demonstrating my issue:
http://jsfiddle.net/4g3a5kqc/15/
var data = [
["1", "abc"],
["2", "def"],
["3", "ghi"],
["4", "jkl"]
],
container = document.getElementById("example"),
hot1;
// This function is a custom renderer that creates a hidden SPAN element/
// icon. In this example, when a user changes the value, the SPAN element
// icon will appear.
function customRenderer(instance, td, row, col, prop, value, cellProperties) {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer; display: none;"></span>';
}
var hot1 = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
cells:
function (row, col, prop) {
var cellProperties = {};
if (col == 0) {
cellProperties.renderer = customRenderer;
}
return cellProperties;
}
});
hot1.addHook('afterChange', afterChange);
// Show the SPAN tag with the icon
// in the right-hand side of the cell.
function afterChange(changes, source) {
console.log(changes, source);
if (source == 'edit' || source == 'autofill') {
$.each(changes,
function (index, element) {
var change = element;
var rowIndex = change[0];
var columnIndex = change[1];
var oldValue = change[2];
var newValue = change[3];
console.log(oldValue, newValue, rowIndex, columnIndex, change);
if (columnIndex != 0) {
return;
}
if (newValue >= 0) {
return;
}
var cellProperties = hot1.getCellMeta(rowIndex, hot1.propToCol(columnIndex));
var td = hot1.getCell(rowIndex, columnIndex, true);
var span = td.getElementsByTagName("span");
$("#" + span[0].id).show();
});
}
}
Due to customRenderer() being called after every change we have to store somewhere cells with spans visible and check for it at the rendering. On the other hand if the span should not be visible (input is valid) we need to remove it from the array of cells wit visible spans. Working fiddle:
http://jsfiddle.net/8vdwznLs/
var data = [
["1", "abc"],
["2", "def"],
["3", "ghi"],
["4", "jkl"]
],
container = document.getElementById("example"),
hot1,
visibleSpans = [];
// This function is a custom renderer that creates a hidden SPAN element/
// icon. In this example, when a user changes the value, the SPAN element
// icon will appear.
function customRenderer(instance, td, row, col, prop, value, cellProperties) {
if (visibleSpans.indexOf(td) > -1) {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer;"></span>';
} else {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer; display: none;"></span>';
}
}
var hot1 = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
cells:
function (row, col, prop) {
var cellProperties = {};
if (col == 0) {
cellProperties.renderer = customRenderer;
}
return cellProperties;
}
});
hot1.addHook('afterChange', afterChange);
// Show the SPAN tag with the icon
// in the right-hand side of the cell.
function afterChange(changes, source) {
console.log(changes, source);
if (source == 'edit' || source == 'autofill') {
$.each(changes,
function (index, element) {
var change = element;
var rowIndex = change[0];
var columnIndex = change[1];
var oldValue = change[2];
var newValue = change[3];
var td = hot1.getCell(rowIndex, columnIndex, true);
console.log(oldValue, newValue, rowIndex, columnIndex, change);
if (columnIndex != 0) {
return;
}
if (newValue >= 0) {
var indexOfSpan = visibleSpans.indexOf(td);
if (indexOfSpan > -1) {
visibleSpans.splice(indexOfSpan, 1);
hot1.render();
return;
}
return;
}
var cellProperties = hot1.getCellMeta(rowIndex, hot1.propToCol(columnIndex));
visibleSpans.push(td);
var span = td.getElementsByTagName("span");
span[0].setAttribute('style', '');
});
}
}

Restrict user to select next row in jqgrid

I am using jqgrid in my project.I have requirement that when user select row and click on edit button of inline toolbar control and modify any data in cell after that instead of click on Save button of inline toolbar control user click(select) any other row at that time.I want to show user message like
Wants to save/discard the modified data
if user click on Save button of message dialog then save the data otherwise discard the data.So please let me know how can I implement it.Till user don’t click on save or discard button don’t select the next row on which user click.
First of all you should use restoreAfterSelect: false option of inlineNav (if you use inlineNav). Seconds you can use beforeSelectRow to implement the required behavior and to call saveRow or restoreRow depend on the user choice.
The simplest implementation of beforeSelectRow could be the following:
beforeSelectRow: function (rowid) {
var $self = $(this),
savedRowInfos = $self.jqGrid("getGridParam", "savedRow"),
editingRowId = savedRowInfos == null || savedRowInfos.length < 1 ?
null : savedRowInfos[0].id;
if (editingRowId != null && editingRowId !== rowid) {
if (confirm("Do you want to save the changes?")) {
$self.jqGrid("saveRow", editingRowId);
} else {
$self.jqGrid("restoreRow", editingRowId);
}
}
}
I used confirm method above. You can see the working code on the demo.
Alternatively one can create asynchronous dialog using jQuery UI dialog for example. Then the code of beforeSelectRow could be the following:
beforeSelectRow: function (rowid) {
var $self = $(this),
savedRowInfos = $self.jqGrid("getGridParam", "savedRow"),
editingRowId = savedRowInfos == null || savedRowInfos.length < 1 ?
null : savedRowInfos[0].id;
if (editingRowId == null || editingRowId === rowid) {
return true; // allow selection
}
$("#dialog-confirm").dialog({
resizable: false,
height: "auto",
width: 650,
modal: true,
buttons: {
"Save the changes": function () {
$(this).dialog("close");
$self.jqGrid("saveRow", editingRowId);
$self.jqGrid("setSelection", rowid);
},
"Discard the changes": function () {
$(this).dialog("close");
$self.jqGrid("restoreRow", editingRowId);
$self.jqGrid("setSelection", rowid);
},
"Continue editing": function () {
var tr = $self.jqGrid("getGridRowById", editingRowId);
$(this).dialog("close");
setTimeout(function () {
$(tr).find("input,textarea,select,button,object,*[tabindex]")
.filter(":input:visible:not(:disabled)")
.first()
.focus();
}, 50);
}
}
});
return false; // prevent selection
}
The corresponding demo is here.

how can I get Index Of selectedRow kendo UI

I use belowe code to get selected code but I need get current Row Index to move up abd down , How can I get row index of selecetd Item :
my code :
$("#btnup").click(function () {
var grid = $("#grid").data("kendoGrid");
var selectedItem = grid.dataItem(grid.select());
if (selectedItem != undefined) {
alert("The Row Is SELECTED");
// here need row index
}
else
alert("NO Row Is SELECTED")
});
Please try with the below code snippet.
$("#btnup").click(function () {
var grid = $("#grid").data("kendoGrid");
var selectedItem = grid.dataItem(grid.select());
if (selectedItem != undefined) {
// I have added selected row index on below code line
alert("The Row Is SELECTED at index: " + grid.select().index());
}
else
alert("NO Row Is SELECTED")
});
Let me know if any concern.

How to add toggle button from jqgrid toolbar to autogenerated context menu

Toggle button in jqgrid top toolbar is defined using Oleg answer as
var autoedit;
$("#grid_toppager_left table.navtable tbody tr").append(
'<td class="ui-pg-button ui-corner-all" >' +
'<div class="ui-pg-div my-nav-checkbox">' +
'<input tabindex="-1" type="checkbox" id="AutoEdit" '+(autoedit ? 'checked ' : '')+'/>' +
'<label title="Toggle autoedit" for="AutoEdit">this text is ignored in toolbar</label></div></td>'
);
$("#AutoEdit").button({
text: false,
icons: {primary: "ui-icon-star"}
}).click(function () {
autoedit = $(this).is(':checked');
});
Answer from how to add standard textbox command to jqgrid context menu is used to autogenerate context menu for grid from toolbar.
In generated context menu for this item only text "this text is ignored in toolbar" appears and selecting it does nothing.
How to make it work or remove this item from context menu?
Look at the demo or the same demo with another themes: this and this.
First of all I modified the code of the jquery.contextmenu.js to support jQuery UI Themes. Then I modified the code more, to be able to create context menu more dynamically. In the modified version of jquery.contextmenu.js one can crate menu and the bindings not only in the onContextMenu, but also in onShowMenu. Inside of onContextMenu one can create just the empty menu
<div id="myMenu"><ul></ul></div>
It is important only if one use dynamically switching of the icons of the text of buttons from the navigator bar.
You can download the modified version of the file here.
In the demo I used the last modification of the code from the answer, so the standard context menu can be still used in the grid on selected text or in the enabled input/textarea fields. The context menu of the browser will be displayed in the case:
I modified the code of createContexMenuFromNavigatorButtons function from the answer to the following:
var getSelectedText = function () {
var text = '';
if (window.getSelection) {
text = window.getSelection();
} else if (document.getSelection) {
text = document.getSelection();
} else if (document.selection) {
text = document.selection.createRange().text;
}
return typeof (text) === 'string' ? text : text.toString();
},
createContexMenuFromNavigatorButtons = function (grid, pager) {
var menuId = 'menu_' + grid[0].id, menuUl = $('<ul>'),
menuDiv = $('<div>').attr('id', menuId);
menuUl.appendTo(menuDiv);
menuDiv.appendTo('body');
grid.contextMenu(menuId, {
bindings: {}, // the bindings will be created in the onShowMenu
onContextMenu: function (e) {
var p = grid[0].p, i, lastSelId, $target = $(e.target),
rowId = $target.closest("tr.jqgrow").attr("id"),
isInput = $target.is(':text:enabled') ||
$target.is('input[type=textarea]:enabled') ||
$target.is('textarea:enabled');
if (rowId && !isInput && getSelectedText() === '') {
i = $.inArray(rowId, p.selarrrow);
if (p.selrow !== rowId && i < 0) {
// prevent the row from be unselected
// the implementation is for "multiselect:false" which we use,
// but one can easy modify the code for "multiselect:true"
grid.jqGrid('setSelection', rowId);
} else if (p.multiselect) {
// Edit will edit FIRST selected row.
// rowId is allready selected, but can be not the last selected.
// Se we swap rowId with the first element of the array p.selarrrow
lastSelId = p.selarrrow[p.selarrrow.length - 1];
if (i !== p.selarrrow.length - 1) {
p.selarrrow[p.selarrrow.length - 1] = rowId;
p.selarrrow[i] = lastSelId;
p.selrow = rowId;
}
}
return true;
} else {
return false; // no contex menu
}
},
onShowMenu: function (e, $menu) {
var options = this, $menuUl = $menu.find('ul:first').empty();
$('table.navtable .ui-pg-button', pager).each(function () {
var $spanIcon, text, $td, id, $li, $a, button,
$div = $(this).children('div.ui-pg-div:first'),
gridId = grid[0].id;
if ($div.length === 1) {
text = $div.text();
$td = $div.parent();
if (text === '') {
text = $td.attr('title');
}
if (this.id !== '' && text !== '') {
id = 'menuitem_' + this.id;
if (id.length > gridId.length + 2) {
id = id.substr(0, id.length - gridId.length - 1);
}
} else {
// for custom buttons
id = $.jgrid.randId();
}
$li = $('<li>').attr('id', id);
$spanIcon = $div.children('span.ui-icon');
if ($spanIcon.length > 0) {
// standard navGrid button or button added by navButtonAdd
$li.append($('<a>')
.text(text)
.prepend($spanIcon.clone().css({
float: 'left',
marginRight: '0.5em'
})));
$menuUl.append($li);
options.bindings[id] = (function ($button) {
return function () { $button.click(); };
}($div));
} else {
button = $div.children("input").data("button");
if (button !== undefined) {
$a = $('<a>')
.text(button.options.label)
.prepend(
$('<label>').addClass("ui-corner-all").css({
float: 'left',
width: '16px',
borderWidth: '0px',
marginRight: '0.5em'//'4px'
}).append(
$('<span>').addClass("ui-button-icon-primary ui-icon " +
button.options.icons.primary)
.css({
float: 'left',
marginRight: '0.5em'
})
)
);
$li.append($a);
if (button.type === "checkbox" && button.element.is(':checked')) {
$a.find('label:first').addClass("ui-state-active");
}
$menuUl.append($li);
options.bindings[id] = (function ($button, isCheckbox) {
if (isCheckbox) {
return function () {
if ($button.is(':checked')) {
$button.siblings('label').removeClass("ui-state-active");
} else {
$button.siblings('label').addClass("ui-state-active");
}
$button.click();
$button.button("refresh"); // needed for IE7-IE8
};
} else {
return function () { $button.click(); };
}
}(button.element, button.type === "checkbox"));
}
}
}
});
return $menu;
}
});
},
autoedit = false;
and fill the check-button in the navigator bar with the code which is changed only a little:
$("#pager_left table.navtable tbody tr").append(
'<td class="ui-pg-button ui-corner-all">' +
'<div class="ui-pg-div my-nav-checkbox">' +
'<input tabindex="-1" type="checkbox" id="AutoEdit" />' +
'<label title="Checkx caption which should appear as button tooltip"' +
' for="AutoEdit">Autoedit</label></div></td>'
);
$("#AutoEdit").button({
text: false,
icons: {primary: "ui-icon-mail-closed"}
}).click(function () {
var iconClass, $this = $(this);
if (!autoedit) { // $this.is(':checked')) {
autoedit = true;
iconClass = "ui-icon-mail-open";
} else {
autoedit = false;
iconClass = "ui-icon-mail-closed";
}
$this.button("option", {icons: {primary: iconClass}});
});
createContexMenuFromNavigatorButtons($grid, '#pager');
UPDATED: One more demo which support buttons added by new inlineNav method you can find here. Additionally I included in the demo the function normalizePagers which I use to improve the look of the pager:
How you can see the contextmenu includes only enabled buttons from the navigator bar.

How to highlight the last selected row after client-side sorting on jqGrid?

I've a jqGrid-based application, and I use loadonce: true in the grid option and sortable: true, sorttype: 'text in the colModel to allow client-side sorting on the data grid. However, I found that, once the data grid is re-sorted, the last selected row will no longer be highlighted. My question is, how to keep the selected row being highlighted across data resorting?
I prepared for you the small demo which keeps the row selection. In the demo I rewrote the code of selectionPreserver used in case of reloadGrid usage having additional parameters: $("#list").trigger("reloadGrid", [{current:true}]);. See the answer for details.
The demo saves the current selection inside of the onSortCol event handler and restore it inside of the loadComplete:
onSortCol: function () {
saveSelection.call(this);
},
loadComplete: function () {
restoreSelection.call(this);
}
How you see the usage is very simple and you can integrate it in your code. The implementation of the saveSelection and restoreSelection is the following:
var lastSelArrRow = [],
lastScrollLeft = 0,
lastSelRow = null,
saveSelection = function () {
var $grid = $(this);
lastSelRow = $grid.jqGrid('getGridParam', 'selrow');
lastSelArrRow = $grid.jqGrid('getGridParam', 'selrow');
lastSelArrRow = lastSelArrRow ? $.makeArray(lastSelArrRow) : null;
lastScrollLeft = this.grid.bDiv.scrollLeft;
},
restoreSelection = function () {
var p = this.p,
$grid = $(this);
p.selrow = null;
p.selarrrow = [];
if (p.multiselect && lastSelArrRow && lastSelArrRow.length > 0) {
for (i = 0; i < lastSelArrRow.length; i++) {
if (lastSelArrRow[i] !== lastSelRow) {
$grid.jqGrid("setSelection", lastSelArrRow[i], false);
}
}
lastSelArrRow = [];
}
if (lastSelRow) {
$grid.jqGrid("setSelection", lastSelRow, false);
lastSelRow = null;
}
this.grid.bDiv.scrollLeft = lastScrollLeft;
};

Resources