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

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

Related

Kendo Grid- Apply CSS style for only numeric columns

I have many grids in my application. some of the columns are numeric ones.
I want to apply a specific css style (direction: ltr) for all numeric columns without specifying is for each one. Is their a way to apply the style on all numeric columns?
Thanks a lot!
Kendo grid has a dataBound event that will be fired once the grid has finished rendering the cells. From this event, you'll be able to loop into the grid's view and column and set each cell css individually.
Note that the type is part of the model, not the column itself.
$.each(kendoGrid.columns, function (index, column) {
//Get the type from the model
var type = kendoGrid.dataSource.options.schema.model.fields[column.field].type;
var jqTd;
//Extra logic to handle locked columns
//nth-child is 1-base
if (columnScan.locked) {
lockCount++;
jqTd = kendoGrid.lockedContent.find("tbody>tr>td:nth-child({0})".formatWith(index + 1));
} else {
jqTd = kendoGrid.tbody.find(">tr>td:nth-child({0})".formatWith(index + 1 - lockCount));
}
if (type == "number") {
jqTd.css("background-color", "red");
}
});

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.

Add or trigger event after inner content to page

I have links on a table to edit or delete elements, that elements can be filtered. I filtered and get the result using ajax and get functions. After that I added (display) the result on the table using inner.html, the issue here is that after filtering the links on the elements not work, cause a have the dojo function like this
dojo.ready(function(){
dojo.query(".delete-link").onclick(function(el){
var rowToDelete = dojo.attr(this,"name");
if(confirm("Really delete?")){
.......
}
});
I need to trigger the event after filtering, any idea?
(I'm assuming that you're using Dojo <= 1.5 here.)
The quick answer is that you need to extract the code in your dojo.ready into a separate function, and call that function at the end of your Ajax call's load() callback. For example, make a function like this:
var attachDeleteEvents = function()
dojo.query(".delete-link").onclick(function(el){
var rowToDelete = dojo.attr(this,"name");
if(confirm("Really delete?")){
.......
}
});
};
Then you call this function both in dojo.ready and when your Ajax call completes:
dojo.ready(function() { attachDeleteEvents(); });
....
var filter = function(someFilter) {
dojo.xhrGet({
url: "some/url.html?filter=someFilter",
handleAs: "text",
load: function(newRows) {
getTableBody().innerHTML = newRows;
attachDeleteEvents();
}
});
};
That was the quick answer. Another thing that you may want to look into is event delegation. What happens in the code above is that every row gets an onclick event handler. You could just as well have a single event handler on the table itself. That would mean there would be no need to reattach event handlers to the new rows when you filter the table.
In recent versions of Dojo, you could get some help from dojo/on - something along the lines of:
require(["dojo/on"], function(on) {
on(document.getElementById("theTableBody"), "a:click", function(evt) {...});
This would be a single event handler on the whole table body, but your event listener would only be called for clicks on the <a> element.
Because (I'm assuming) you're using 1.5 or below, you'll have to do it a bit differently. We'll still only get one event listener for the whole table body, but we have to make sure we only act on clicks on the <a> (or a child element) ourselves.
dojo.connect(tableBody, "click", function(evt) {
var a = null, name = null;
// Bubble up the DOM to find the actual link element (which
// has the data attribute), because the evt.target may be a
// child element (e.g. the span). We also guard against
// bubbling beyond the table body itself.
for(a = evt.target;
a != tableBody && a.nodeName !== "A";
a = a.parentNode);
name = dojo.attr(a, "data-yourapp-name");
if(name && confirm("Really delete " + name + "?")) {
alert("Will delete " + name);
}
});
Example: http://fiddle.jshell.net/qCZhs/1/

Using jQGrid and jQUery tabs how to oprimize the number of grids

I have 3 different tabs where i am displaying data using jQGrids(each tab contain one grid).
But i just thought that my grids are completely the same, only the difference is that they using different url to get data.
So I have three similar girds on each tab only with different urls:
First: url: '/Home/GetData?id=1' Second: url: '/Home/GetData?id=2' and Third: url: '/Home/GetData?id=3'
So i was thinking that may be i may declare grid only once and than on each tab click a can pass the url to load data? So on each tab click jQGrid will be populating from the new url.
May be some one may have any ideas about that?
Or may be some one may have better ideas how to reduce "jQGrid copy-paste" in that case?
UPDATE 0:
Nearly get it work i mean it is working but there is one small problem,
When i am switching tabs the header of the grid getting lost...and some jqgrid formatting as well.
here is my code:
$("#tabs").tabs({
show: function (event, ui) {
if (ui.index == 0) {
//$("#Grid1").appendTo("#tab1");
//$("#Grid1Pager").appendTo("#tab1");
//When Appending only pager and grid div, header getting lost so i've append the whole grid html instead
$("#gbox_Grid1").appendTo("#tab1");
changeGrid("#Grid1", 1);
}
else if (ui.index == 1) {
//$("#Grid1").appendTo("#tab2");
//$("#Grid1Pager").appendTo("#tab2");
$("#gbox_Grid1").appendTo("#tab2");
changeGrid("#Grid1", 2);
}
else if (ui.index == 2) {
//$("#Grid1").appendTo("#tab3");
//$("#Grid1Pager").appendTo("#tab3");
$("#gbox_Grid1").appendTo("#tab3");
changeGrid("#Grid1", 3);
}
}
});
function changeGrid(grid, id) {
$(grid).jqGrid('setGridParam', {
url: '/Home/GetData?id=' + id
});
$(grid).trigger('reloadGrid');
}
UPDATE 1
All right, i've changed the code to append the whole grid instead of appending grid div and pager only. So it is working like that.
You can basically make the tabs as regular buttons that will call some function which sets new URL parameter to the grid and reloads it.
The function should be something like this:
function changeGrid(grid, id) {
$(grid).jqGrid('setGridParam', {
url: '/Home/GetData?id=' + id, page: 1
});
$(grid).trigger('reloadGrid');
}
Note that I set the page to 1. Keep in mind that you might need to set the default sorting column or something similar depending on your solution.
UPDATE
If you really want to go with the tabs, the 'show' event handler can be simplified.
Try this:
$("#tabs").tabs({
show: function (event, ui) {
var id = ui.index + 1;
$("#gbox_Grid1").appendTo("#tab" + id);
$("#Grid1").jqGrid('setGridParam', {
url: '/Home/GetData?id=' + id
});
$("#Grid1").trigger('reloadGrid');
}
});

highlight error cell or input when validation fails in 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.

Resources