highlight error cell or input when validation fails in jqgrid - jqgrid

I am using jqgrid inline editing with validation in grid using edit rules . i want to add class to highlight errors(eg: ui-state-error) for the input which fails in validation .
i can set class to highlight error using this
jQuery('#'+grid_id).jqGrid('setCell',row_id,errfields[a],'','ui-state-error',{color: 'blue'});
But it is not working in jqgrid when inbuilt validation fails .
How do i highlight the validation error triggered cell/input .

The demo shows how the probelm can be solved:
In the demo the columns "Amount", "Tax" and "Total" will be validated with the following validation rule:
editrules:{required:true,number:true}
On any validation error the first input field where the validation failed dditional class "ui-state-error" will be added. It is the standard jQuery UI CSS class. Addionally I set focus to the input field.
For the implementation I overwride (chain) the default implementation of the methods $.jgrid.checkValues and $.jgrid.hideModal. Here is the corresponding code:
var grid = $("#list");
grid.jqGrid({
// define all jqGrid options
});
var originalCheckValues = $.jgrid.checkValues,
originalHideModal = $.jgrid.hideModal,
iColWithError = 0;
$.jgrid.checkValues = function(val, valref,g, customobject, nam) {
var tr,td,
ret = originalCheckValues.call(this,val, valref,g, customobject, nam);
if (!ret[0]) {
tr = g.rows.namedItem(editingRowId);
if (tr) {
$(tr).children('td').children('input.editable[type="text"]').removeClass("ui-state-error");
iColWithError = valref; // save to set later the focus
//error_td_input_selector = 'tr#'+editingRowId+' > td:nth-child('+(valref+1)+') > input.editable[type="text"]:first';
td = tr.cells[valref];
if (td) {
$(td).find('input.editable[type="text"]').addClass("ui-state-error");
}
}
}
return ret;
};
$.jgrid.hideModal = function (selector,o) {
var input, oldOnClose, td,
tr = grid[0].rows.namedItem(editingRowId);
if (tr) {
td = tr.cells[iColWithError];
if (td) {
input = $(td).children('input.editable[type="text"]:first');
if (input.length > 0) {
oldOnClose = o.onClose;
o.onClose = function(s) {
if ($.isFunction(oldOnClose)) {
oldOnClose.call(s);
}
setTimeout(function(){
input.focus();
},100);
};
}
}
}
originalHideModal.call(this,selector,o);
};

In my project, I combine to use jqgrid and jquery validation plugin to examine and highlight errors, to provide unified look and feel in the entire application. You can use rowId_columnName as id to find the editor (input, select, etc.), e.g. $('#1_name') for name column in row 1 and then use the jquery object to add a rules, e.g. $('#1_name').rules('add', {required:true}) to add a rule to enforce that the cell is required, then calling $('#1_name').valid() to force a validation pass when value is submitted, e.g. before calling jqgrid saveRow method. Open the link for the plugin to know more about rules method and valid method.

Related

Kendo grid getKendoGrid not working with extended kendo grid

I am trying to implement Kendo Grid "SelectAll" feature for our extended Kendo grid. When "SelectAll" Column included, UI is rendering properly But, the "Select All" header checkbox click is not working. Noticed that getKendoGrid method is not working with extended Kendo grid.
Kendo.web.js....
_headerCheckboxClick: function (e) {
var that = this,
checkBox = $(e.target),
checked = checkBox.prop('checked'),
**parentGrid = checkBox.closest('.k-grid.k-widget').getKendoGrid();**
if (that !== parentGrid) {
return;
}
if (checked) {
that.select(parentGrid.items());
} else {
that.clearSelection();
}
},
You can try to use checkBox.closest('.k-grid.k-widget').data("kendoGrid") instead of getKendo* method.
that function change is name to the parameter d
o = <your_kendo_plugin_name>
d = "kendo" + o
so you should use the function kendoGrid() instead of getKendoGrid(),

jqGrid rowNum option issue

Assume that row numbers is changed from 10 to 30 in navgrid and that we handle onPaging like so:
...
onPaging: function(pgbtn) {
var rowNum = $(this).getGridParam('rowNum');
return 'stop';
}
In jqGrid 4.4.0 rowNum will be 30.
In jqGrid 4.7.0 rowNum will be 10.
Is this expected behaviour because I think rowNum should be 30?
The order of the execution is changed in (compare the line in jqGrid 4.7.0 with the line in jqGrid 4.4.0). jqGrid first changed the rowNum``and then calledonPaging` in jqGrid 4.4.0, but in jqFeid 4.7.0 the oder is changed.
To access to the new value of rowNum one should get the value of rowNum from the corresponding <select> control directly. If you use the pager at the bottom of the grid then the corresponding code could be the following:
onPaging: function (pgButton) {
var p = $(this).jqGrid("getGridParam"),
newRowNum = parseInt($(p.pager).find(".ui-pg-selbox").val());
if (...) { // some stop criteria
return "stop";
}
}
If you use toppager: true option then jqGrid create the pager on the top of the grid and then it change the value of toppager parameter from true to the selector id of the pager. So you can use the code like
onPaging: function (pgButton) {
var p = $(this).jqGrid("getGridParam"),
newRowNum = parseInt($(p.toppager).find(".ui-pg-selbox").val());
if (...) { // some stop criteria
return "stop";
}
}
which just use p.toppager instead of p.pager in the previous code example.
In case of usage both top and bottom pagers you have to get both values and choose the value which is not equal to the value of rowNum parameter:
onPaging: function (pgButton) {
var p = $(this).jqGrid("getGridParam"),
rowNumBottom = parseInt($(p.pager).find(".ui-pg-selbox").val()),
rowNumTop = parseInt($(p.toppager).find(".ui-pg-selbox").val()),
newRowNum = p.rowNum === rowNumTop ? rowNumBottom: rowNumTop;
if (...) { // some stop criteria
return "stop";
}
}
By the way there are exist close problem in case of calling onPaging after other changing in the pager, for example if the user typed new value in the input box with new pager number.
I'm developing now free jqGrid as my fork on github. I change the code of jqGrid so that onPaging receives the second parameter which is object with the properties newPage, currentPage, lastPage, currentRowNum and newRowNum. The corresponding jQuery event jqGridPaging are added too. Moreover I have changed the value of the first parameter so that it corresponds the documentation and the value will be the string "first", "last", "prev" or "next" in case when the user clicked on the corresponding pager button. The version 4.7 used in reality the id of the corresponding pager buttons instead of "first", "last", "prev", "next". So the strings "first", "last", "prev", "next" could be appended with "_" and the id of the pager (or toppager).
Thus one can just use options.newRowNum or options.currentRowNum directly in the code of callback:
onPaging: function (pgButton, options) {
// one can use options.newRowNum directly
// the value options.currentRowNum is identical to
// $(this).jqGrid("getGridParam", "rowNum")
if (...) { // some stop criteria
return "stop";
}
}
In the case of top and bottom pagers, I would add to Oleg's response:
onPaging: function (pgButton) {
var p = $(this).jqGrid("getGridParam"),
rowNumBottom = parseInt($(p.pager).find(".ui-pg-selbox").val()),
rowNumTop = parseInt($(p.toppager).find(".ui-pg-selbox").val()),
newRowNum = p.rowNum === rowNumTop ? rowNumBottom: rowNumTop;
if (...) { // some stop criteria
return "stop";
}
// update the current value so subsequent changes are detected
p.rowNum = newRowNum;
}
This handles the case that the user changes the value on the top pager, then changes it again on the bottom pager. The code above will keep detecting the top pager value.

How to dynamically update other row fields in a KendoUI grid?

In my KendoUI datasource, I have the following defined:
change: function (e) {
if (e.action === "itemchange") {
// auto-format Display As
var geoDisplay, geoUrl;
if (e.items[0].GeoState.length > 0) {
geoDisplay = e.items[0].GeoCity + ", " + e.items[0].GeoState;
} else {
geoDisplay = e.items[0].GeoCity;
}
//this.dataItem(this.select()).GeoDisplay = geoDisplay;
e.items[0].GeoCity = "updated: " + e.items[0].GeoCity; // visually updates if editing this field
e.items[0].GeoDisplay = geoDisplay; // field is not updated
}
console.log("change: " + e.action);
console.log(e);
// do something else with e
},
Essentially I want to update other fields on a row being edited based on a field's input.
In this example, GeoCity is updated. The itemchange event is fired and only the GeoCity field gets updated with the new value. However I can see from the data that the other fields' data have been updated.
I have tried doing a .sync() and a few other methods to get this to appear, but no luck so far.
Incidentally, my grid is defined within an AngularJS directive and it's onEdit event isn't what I'm looking for, as I want the events that fire when each field is updated, not the whole row.
How can I get the other fields to visually update?
I managed to solve the issue by placing the following code in the data source code:
change: function (e) {
if (e.action === "itemchange") {
// auto-format Display As
var thisRow = $("#accountGeoLocationEditorGrid tbody").find(".k-grid-edit-row");
// update geo display
if (e.field === "GeoCity" || e.field === "GeoState") {
var geoDisplay, geoUrl;
if (e.items[0].GeoState.length > 0) {
geoDisplay = e.items[0].GeoCity + ", " + e.items[0].GeoState;
} else {
geoDisplay = e.items[0].GeoCity;
}
if (e.items[0].GeoDisplay.length == 0) {
e.items[0].GeoDisplay = geoDisplay;
thisRow.find("input[name=GeoDisplay]").val(geoDisplay);
}
}
}
I was really looking for another way to do this, as I don't really want to be doing DOM lookup, etc in a defined datasource.
Other suggestions welcome.
Did you try the grid refresh() method? At the end of your changes in the change event, call this line (with your grid's correct id):
$("#grid").data("kendoGrid").refresh();
I've tested this on my grid and kendo's samples and it works fine like this. You are editing the datasource but the grid is not aware of the extra changes you have done, except the cell that was edited. Calling refresh will update all the cells on the grid to reflect the datasource.

Fetch dropdown values or id from an inline grid

I want to fetch dropdown values or IDs. I am using a dropdown control in an inline editing kendo grid. I'm trying to obtain the values using the change function. My demo code is:
function gridEdit(e)
{
griddata = $('#CodeConfiguration').data("kendoGrid");
codeType = e.container.find(":input[name=CodeType_032]");
fixedCode = e.container.find(":input[name=FixedCode]");
alert(codeType.id);
codeType.change(function()
{
if(codeType.val() == 273)
{
fixedCode.attr('disabled',true);
}
});
}
I want to fetch CodeType dropdown values. Please suggest an appropriate solution.
Basically if your DropDownList is bound to field from the Grid model, then you can directly get the value from the Model.
e.g.
function onEdit(e) {
var codetype = e.model.CodeType;
}

I want to display the applied filter criteria on the Kendo UI Grid

How can I display any applied filter criteria on the Kendo UI Grid.
I would like to have a readonly display, of the applied criteria.
Current functionality does allow user to apply filter, but that the user has to go to the filter menu to look for the filter details.
The Kendo UI data source doesn't have a filter event, so you'd need to implement that yourself. Then when the event is triggered, you can get the current filter and format it in whatever way you want it displayed.
For example:
var grid = $("#grid").kendoGrid(...);
// override the original filter method in the grid's data source
grid.dataSource.originalFilter = grid.dataSource.filter;
grid.dataSource.filter = function () {
var result = grid.dataSource.originalFilter.apply(this, arguments);
if (arguments.length > 0) {
this.trigger("afterfilter", arguments);
}
return result;
}
// bind to your filter event
grid.dataSource.bind("afterfilter", function () {
var currentFilter = this.filter(); // get current filter
// create HTML representation of the filter (this implementation works only for simple cases)
var filterHtml = "";
currentFilter.filters.forEach(function (filter, index) {
filterHtml += "Field: " + filter.field + "<br/>" +
"Operator: " + filter.operator + "<br/>" +
"Value: " + filter.value + "<br/><br/>";
if (currentFilter.filters.length > 1 && index !== currentFilter.filters.length - 1) {
filterHtml += "Logic: " + currentFilter.logic + "<br/><br/>";
}
});
// display it somewhere
$("#filter").html(filterHtml);
});
See demo here.
Note that filters can be nested, so once that happens, this example code won't be enough - you'll have to make the code that converts the filters to HTML recursive.
In order to augment all data sources with the "afterfilter" event, you have to change the DataSource protototype instead of changing it on your instance:
kendo.data.DataSource.fn.originalFilter = kendo.data.DataSource.fn.filter;
kendo.data.DataSource.fn.filter = function () {
var result = this.originalFilter.apply(this, arguments);
if (arguments.length > 0) {
this.trigger("afterfilter", arguments);
}
return result;
}
If you want to integrate the whole thing into all grid widgets, you could create a new method filtersToHtml which gets you the HTML represenatation and add it to kendo.data.DataSource.fn like demonstrated above (or you could create your own widget derived from Kendo's grid); in the same way you could add a method displayFilters to kendo.ui.Grid.fn (the grid prototype) which displays this HTML representation in a DOM element whose selector you could pass in with the options to your widget (you could ultimately also create this element within the grid widget). Then instead of triggering "afterfilter" in the filter method, you could call displayFilters instead.
Considering the complexity of the complete implementation which always displays filters, I'd suggest extending the Kendo grid instead of simply modifying the original code. This will help keep this more maintainable and gives it a bit of structure.
how about combining two filters of grid.
this way the user can see the selected filter in text box and even remove it by hitting the 'x' button on filtered column text box.
you can do this by setting grid filterable like this
filterable: {
mode: "menu, row"
}
the documentation and example is in here

Resources