Is there a way to retrieve all editable cells from kendo grid? - kendo-grid

I have a kendo grid in which fields are editable based on some condition like:
//var isEditable= some condition
fields: {
Id: { type: "int", editable: false },
Amount: {type: "number", editable: isEditable},
}
I want to get all editable cells and perforn something on them before they are displayed.
Currently i'm using dataBound event iterate rows and cells and find desired cells
dataBound: function(e){
var rows = e.sender.tbody.children();
for (var j = 0; j < rows.length; j++) {
var row = $(rows[j]);
if (isEditable){
var cell1 = row.children().eq("hardcoded index");
var cell2 = row.children().eq("hardcoded index 2");
var cell3 = row.children().eq("hardcoded index 3");
......
......
// perform action
}
}
Is there a better approach to achieve that?

Since you want to do something to the editable element before display, I would use a template to accomplish that. Here is an example that turns the background color red if the Amount field is editable:
<script id="editableTemplate" type="text/x-kendo-template">
#if (Editable) { #
<div style='background-color:red'>#=Amount#</div>
# } else { #
<div>#=Amount#</div>
# } #
<script>
Another way to approach this is to take parameters by wrapping the template in a function:
function foo(isEdit, value) {
if(isEdit){
return "<div style='background-color:red'>" + value + "</div>";
} else {
return "<div>" + value + "</div>";
}
}
You can then set the column template as:
{
field: "Amount",
type: "number",
template: function(data) {
return kendo.template("#=foo(isEditable, Amount)#")
},
editable: isEditable
}
Here is a basic fiddle.

Related

ag-Grid - Is it possible to create a floating menu for each row?

I'm trying to create a menu that appears when a user hovers on a row, just like in the image below.
I did not find any built-in option to achieve this. Also tried using a custom CellRenderer function to create an element that I could move around later, but that didn't work as expected since it presented some other challenges (css wise) and was not really achieving the goal.
Is there a way to build this kind of menus in ag-Grid?
To work around the problem, you could use onCellMouseOver & onCellMouseOut methods:
var gridOptions = {
columnDefs: columnDefs,
onCellMouseOver : onCellMouseOver,
onCellMouseOut: onCellMouseOut,
...
};
Define both functions:
var onCellMouseOver = function(event){
//Get current row
var rowIndex = event.node.rowIndex;
var row = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
//Set current row as not selected - in order to base on 'cellStyle' function
row.setSelected(true);
//Setup refresh params
var params = {
force: true, //Force refresh as cell value didn't change
rowNodes: [row]
};
//Refresh current row cells
gridOptions.api.refreshCells(params);
}
var onCellMouseOut = function(event){
//Get current row
var rowIndex = event.node.rowIndex;
var row = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
//Set current row as not selected - in order to base on 'cellStyle' function
row.setSelected(false);
//Setup refresh params
var params = {
force: true, //Force refresh as cell value didn't change
rowNodes: [row]
};
Then define 'cellStyle' function for your column:
var columnDefs = [
{headerName: "your_column_name", field: "your_column",
cellStyle: function(params) {;
console.log('Is row selected', params.node.selected);
if (params.node.selected) {
return {display : 'none'};
} else {
return {display : 'inherit'};
}
}
}
];
You can find more about data refresh here: https://www.ag-grid.com/javascript-grid-refresh/
The full implementation of the code above might be found here: Working example
Second solution, edited after comments:
Another way is to use css classes to achieve the result.
{
headerName: "Price",
field: "price",
cellStyle: { "text-align": "center" },
cellRenderer: function(params) {
return (
"<div class='buttons'>" +
"<div class='back'>" +
params.value +
"</div>" +
"<div class='front'><button>Option A</button><button>Option B</button></div>" +
"</div>"
);
}
Buttons are shown on hover based on .ag-row-hover ag-grid class:
.front {
display: none;
}
.ag-row-hover .front {
display: inherit;
}
Working example

Kendo UI grid filter cell that contains an array

I want to filter a specific column on a Kendo Grid that contains an array.
The grid configuration is
var resultsGrid = this.kendoGrid({
dataSource:{
data:[],
pageSize:20
},
sortable: {
mode: "multiple",
allowUnsort: true
},
filterable: {
extra: false,
operators: {
string: {
startswith: "Starts with",
eq: "Is equal to",
neq: "Is not equal to"
}
}
},
pageable: {
pageSizes: true,
buttonCount: 5
},
scrollable: false,
columns: resultsColumns
}).data("kendoGrid");
return resultsGrid;
The columns configuration is
var resultsColumns = [
{field: "keys", filterable: true, headerTemplate: function(){return Ec.translatedLabel("authorityEntryCode");}, template: '#for(var i = 0; i < keys.length; i++){# #=keys[i].name# = #=keys[i].value# <br> #}#'},
{field: "state", filterable: true, headerTemplate: function(){return Ec.translatedLabel("state");}},
{field: "startDate", filterable: false, headerTemplate: function(){return Ec.translatedLabel("startDate");}},
{command: initGridCommands(), headerTemplate: function(){return Ec.translatedLabel("actions");}}
];
and I want to filter column with the field keys
The field keys is an array of object that contains name and value and I want to filter with the value.
For example
Example of the Grid
So when the user adds a1 as in the screenshot to be filtered the first row.
Please if you have an answer on that it will help me alot, thanks.
Unfortunately this is rather difficult to do in my opinion. The general process would require binding to the filterMenuInit event, removing the contents of the default filter pop up with your own form and then performing the filtering manually on the specific fields you want. I'm not aware of a built in way to perform filtering on an array field. A hacky version overriding only what's required could be like:
filterMenuInit: function(e) {
if (e.field == "keys") {
var filterButton = e.container.find("button[type=submit]");
var clearButton = e.container.find("button[type=reset]");
var dataSource = jQuery("#grid").data("kendoGrid").dataSource;
//Get rid of default filter button...
filterButton.remove();
clearButton.parent().prepend("<button type='button' class='k-button k-primary'>Filter</button>");
var filterText = e.container.find(".k-textbox");
filterButton = e.container.find("button[type=button]");
filterButton.click(function(e) {
e.preventDefault();
dataSource.filter([
{
field: 'keys',
operator: function (items, filterValue) {
for(var i = 0; i < items.length; i++) {
if(items[i].value == filterText.val()) {
return true;
}
}
return false;
},
value: filterText.val()
}
]);
});
clearButton.click(function() {
dataSource.filter([]); //clear filters...
});
}
},
This code is quick and dirty so I'd encourage you to read the docs concerning the filterMenuInit event and data source filtering to come up with a cleaner solution. Here is a snippet as well.

YADCF Apply AND Filterring to Multiple Selections From a JSON Array

I want to apply AND filtering to multiple selections from a JSON array.
'Classification' Data:
Row 0: [Cats, Dogs]
Row 1: [Cats]
Row 2: [Birds, Cats, Dogs]
Filter selection: Cats and Dogs
Result: Display Rows 0 and 2
But (1) this results in OR filtering, and (2) the filter selection choices are the entire contents of each row. So the rows in the picker look like:
Cats, Dogs
Cats
Birds, Cats, Dogs
When the choices should look like:
Birds
Cats
Dogs
Here is the code:
var call = $.ajax({
url: "https://.../_vti_bin/listdata.svc/DocLib?$expand=Classification",
type: "GET",
dataType: "json",
headers: {Accept: "application/json;odata=verbose"}
});
call.done(function (data,textStatus, jqXHR){
myData = data.d.results;
var dtTable = $('#example').DataTable({
data: myData,
columns:[
{data: "Classification.results[, ].Value"}
],
stateSave: true
});
yadcf.init(dtTable, [
{column_number:0,
filter_type: "multi_select"
}]);
});
Note - I read this and wanted to add that data choices in the rows is always in the same order. So there isn't an issue of one row being:
[Dogs, Birds, Cats]
Also, when I try to use
text_data_delimiter:","
I get the error:
SCRIPT5007: Unable to get property 'Value' of undefined or null reference
jquery.dataTables.yadcf.js, line 412 character 4
Thanks, Daniel!
Working JS Fiddle answer.
$(document).ready(function() {
var dtTable= $('#example').DataTable({});
function myCustomFilterFunction(filterVal, columnVal) {
if (filterVal === null) {return true;}
if (filterVal){
var found;
var myElement;
var foundTout = 0;
var nbElemSelected = filterVal.length;
for (i=0; i<nbElemSelected; i++)
{
myElement = filterVal[i];
switch (myElement) {
case 'Starch':found = columnVal.search(/Starch/g);
break;
case 'Fruit':found = columnVal.search(/Fruit/g);
break;
default:found = 1;
break;
}
if (found !== -1) {foundTout++;}
}
if (foundTout == filterVal.length) {return true;}
else {return false;}
}
}
yadcf.init(dtTable, [
{column_number:1,
select_type: "select2",
filter_type: 'multi_select_custom_func',
custom_func: myCustomFilterFunction,
filter_reset_button_text:"Clear",
filter_default_label:"select",
data: [
{value: 'Starch', label: 'Starch'},
{value: 'Fruit', label: 'Fruit'}
]
}]);
});

How To Add Row at Bottom of Kendo Grid Dynamically

We use Kendo Grid for heads down data entry in an accounting application. We need the grid to behave similar to QuickBooks. Specifically, users should be able to:
Tab between cells
Automatically advance to the next row when tabbing off the last cell in a row.
Automatically add a new row when tabbing off the last cell of the last row.
However, we're having difficulty achieving this behavior. The last cell on the last row does not get saved before adding a new row to the bottom of the grid. If, however, we add a bogus column as the last column the proper behavior is achieved, but you have to tab through an extra, needless column which is unacceptable. The user needs to be able to enter and tab with new rows being added automatically. Here's the code:
function createGrid() {
var grid: any = $("#" + target).kendoGrid({
dataSource: gridDs,
edit: gridCellEdit,
editable: {
createAt: 'bottom'
},
filterable: true,
sortable: true,
navigatable: true,
resizable: true,
reorderable: true,
scrollable: { virtual: true },
columns: gridColumns,
dataBound: monitorKeyboard
});
}
function gridCellEdit(e) {
var input = e.container.find("input");
input.focus(function (e) {
input.select();
});
input.focus();
}
function monitorKeyboard(e) {
var grid = $('#' + e.sender.wrapper[0].id).data("kendoGrid");
$(grid.tbody).on("keydown", "td", function (e) {
// Monitor tabbing through columns
if (e.keyCode == 9) {
var row: any = $(this).closest("tr");
var rowIndex: number = $("tr", grid.tbody).index(row);
var colIndex: number = $("td", row).index(this);
var count: number = grid.dataSource.total();
var lastColIndex = row[0].cells.length - 1;
if (rowIndex == count - 1 && colIndex == lastColIndex) {
e.stopImmediatePropagation();
e.preventDefault();
grid.addRow();
grid.saveRow();
}
}
});
}

How to disable the Default sorting applied to groups in Kendo Grid

element.kendoGrid({
dataSource: {
data: scope.people,
group: {
field: "name"
}
},
groupable: true,
sortable: false,
pageable: {
refresh: true,
pageSizes: true
},
columns: scope.columns
});
Passed Data Source
$scope.people = [man1, man2, man3, man4];
var man1 = new Man('Test name2', 25);
var man2 = new Man('Test name1', 28);
var man3 = new Man('Test name1', 21);
var man4 = new Man('Test name3', 21);
Actual REsult :
Group are displaying in following order
First Name : Test name 1
First Name : Test name 2
First Name : Test name 3
Expected Result :
Group should display in following order
First Name : Test name 2
First Name : Test name 1
First Name : Test name 3
How do we achieve this?
By default groups are getting displayed in ascending order. But I want the order of group as it is there in the DataSource
If you can add your data through Ajax, then it's not too hard. I haven't found a way to do it without ajax though.
Your ajax would look like this:
$.ajax({
...[add your data call info here]...
}).done(function(result) {
var data = result.d.results; //this may be different for others
var sortNum = 1;
var lastVal;
for (var i = 0; i < data.length; i++) {
var val = data[i]["Firstname"];
if (!lastVal) {
lastVal = val;
}
if (val !== lastVal) {
sortNum++;
lastVal = val;
}
data[i]["SortOrder"] = sortNum;
}
});
This is if you just want to pass the data as is into your kendo grid.
Now that you have a sort column, tell kendo to group on that new column and replace the text with the original group column to display the names correctly.
//fetch FirstName value and return it to display instead of SortOrder value
function getHeader(val) {
var $data = $('.grid').data('kendoGrid').dataSource.data();
for (var i = 0; i < $data.length; i++) {
if ($data[i].SortOrder === val.value) {
return data[i].FirstName + '';
}
}
}
$('.grid').kendoGrid({
//... do all your normal kendo initialization, I'll just add the stuff you need to change
dataSource: {
schema: {
model: {
fields: { //add the new SortOrder column
SortOrder: {
type: 'number'
}
}
}
},
group: {
field: "SortOrder"
}
},
columns: [{ //add the new SortOrder column, but call the getHeader function to override the value displayed
field: "SortOrder",
hidden: true,
groupHeaderTemplate: getHeader
}]
});
That should be all you need to do. Hope this helps.