Database driven Kendo Grid column - kendo-ui

Is it possible to enumerate the grid columns eg (title and width) coming from a database table?

You will need to make an ajax call for that. Derive the column names from the table and then you can make modifications.
For e.g.
$.ajax({
url:actionUrl, //Url of the Method for fetching names of the columns and its count
success: function(result){
for (var i = 0; i < result.columnsCount; i++) { //running the loop based on number of columns needed
columns.push({
field: result.columnName, //set the columnNames from the Db as field
title: result.Header //specifying the columns title
});
}
}
});

You can try the following:
$(document).ready(function() {
var model = kendo.observable({
gridRows: []
});
var columns = [];
for (var i = 0; i < 4; i++) {
var entryIndex = "entries[" + i + "]";
columns.push({
field: i,
title: "Column " + i
});
}
var configuration = {
resizable: true,
columns: columns
};
var timeEditGrid = $("#grid").kendoGrid(configuration).data("kendoGrid");
kendo.bind($('#example'), model);
});
http://jsfiddle.net/4sM7g/

Related

Filtering a single column with OR operator

Would like to do filtering in kendo grid within the same column for getting a union of values coming from a multiselect field:
$('#btnSearchRoles').click(function (e) {
e.preventDefault();
//process searched roles
var multiselect = $("#RoleSubroleId").data("kendoMultiSelect");
// get data items for the selected options.
var dataItem = multiselect.dataItems();
var filterCode = "[";
for (var i = 0; i < dataItem.length; i++) {
filterCode += "{ field: 'RolesAsString', operator: 'contains', value: '" + dataItem[i].Name + "'},"
}
filterCode += "]";
//start filtering
var dataSource = $("#grid").data('kendoGrid').dataSource;
dataSource.filter({
logic: "or",
filters: filterCode
});
});
Even though filterCode gets correctly populated the filters do not reach the DataSourceRequest request parameter.
I used push method for JS arrays to replace string composition of the filter:
$('#btnSearchRoles').click(function (e) {
e.preventDefault();
//process searched roles
var multiselect = $("#RoleSubroleId").data("kendoMultiSelect");
// get data items for the selected options.
var dataItem = multiselect.dataItems();
var setFilter = { logic: "or", filters: [] };
for (var i = 0; i < dataItem.length; i++) {
setFilter.filters.push({ field: "RolesAsString", operator: "contains", value: dataItem[i].Name });
}
//start filtering
var dataSource = $("#grid").data('kendoGrid').dataSource;
dataSource.filter(setFilter);
});

Add custom command to Kendo UI dynamic datasource / grid

I'm using Kendo UI javascript framework in an ASP.NET MVC application.
I have to load dynamic data, provided by my server, in my Kendo UI Grid, so I don't want to use datasource schema and columns definition, in no case.
An example of my data is : PersonID, Data1, Data2, Date3 ...
To load dynamic data in Kendo UI Grid I use the following code: (JsFidlle Example)
var grid = $("#grid").kendoGrid({
scrollable: false,
sortable: true
}).data("kendoGrid");
var ds = grid.dataSource;
grid.columns = [];
ds.data([{one: 1, two: 1, three: 3, four: 4}]);
Starting from this example, I'm curious to know if, with this management, I can put in each row a command / custom command like "Delete". (Example)
Eventually, how can I handle the command's behavior ? (would be nice to see a confirm window after the click over the command)
Thanks for the attention !
Get your data first, then create an array for the grid columns based on the data and add a column for the buttons.
Create the grid and attach handler to every button.
http://jsfiddle.net/cp67fpw1/2/
Creating the grid:
var columns = [],
data = [{
one: 1,
two: 1,
three: 3,
four: 4,
five: 5
}],
grid;
for (var cx in data[0]) {
if (data[0].hasOwnProperty(cx)) {
columns.push({
field: cx
})
}
}
columns.push({
field: '',
template: '<a class="k-button" command="doit">do it</a><a class="k-button" command="doitagain">do it again</a>'
});
grid = $("#grid").kendoGrid({
columns: columns,
dataSource: new kendo.data.DataSource({
data: data
}),
scrollable: false,
sortable: true
}).data("kendoGrid");
Adding the button handler:
$('#grid').on('click', '[command="doit"]', doit);
function doit(e) {
var dataItem = grid.dataSource.getByUid($(this).closest('tr').data('uid'));
}
I resolved out with this solution : https://jsfiddle.net/Endrik/smLfh67e/1/
It's very similar to Frederic solution but with few changes.
1) I start from a datasource object, cause I will get my data from remote
If you change the type of data loading in the DataSource object, the example should work equally.
var myDataSource = new kendo.data.DataSource({
data: [{
one: "1",
two: "2",
three: "3",
four: "4"
}, {
one: "5",
two: "6",
three: "7",
four: "8"
}]
});
myDataSource.fetch();
2) In order to have dynamic columns, I have to convert the data present in my datasource object into an array of values. (Like Frederic's startup collection of objects)
var myDataSourceRowsNumber = myDataSource.total();
var rows = [];
var columns = null;
var columnsCount = 0;
for (var i = 0; i < myDataSourceRowsNumber; i++) {
var entryArray = [];
var dataItem = myDataSource.at(i);
columns = [];
for (var field in dataItem) {
if (dataItem.hasOwnProperty(field) &&
field != 'parent' &&
field != 'uid' &&
field != '_events') {
columns.push({
field: field,
value: dataItem[field.toString()]
});
}
}
columnsCount = columns.length;
for (var j = 0; j < columnsCount; j++) {
entryArray.push(dataItem[columns[j].field]);
}
rows.push(kendo.observable({
entries: entryArray
}));
}
var viewModel = kendo.observable({
gridRows: rows
});
3) At the end, I create a new Kendo UI grid with my definition of columns.
var finalColumns = [];
for (var k = 0; k <= columnsCount; k++) {
var entryIndex = "entries[" + k + "]";
if (k != columnsCount) {
finalColumns.push({
field: entryIndex,
title: columns[k].field
});
} else {
finalColumns.push({
command: [{
name: "CustomDelete",
text: "Delete",
className: "custom-delete-btn ",
imageClass: "k-icon k-i-close",
click: ManageDeleteButtonClick
}],
title: "Actions"
});
}
}
var configuration = {
editable: true,
sortable: true,
scrollable: false,
columns: finalColumns
};
function ManageDeleteButtonClick(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.target).closest("tr"));
if (confirm('Are you sure you want to delete this record ?')) {
// AJAX CALL
var dataSource = $("#grid").data("kendoGrid").dataSource;
dataSource.remove(dataItem);
}
}
var myGrid = $("#grid").kendoGrid(configuration).data("kendoGrid");
kendo.bind($('#example'), viewModel);

SlickGrid filter not working

I am fairly new to SlickGrid. I am trying to make SlickGrid filter work but no luck. I am following the example (http://mleibman.github.io/SlickGrid/examples/example4-model.html).
Below is my source code.
$(document).ready(function() {
var tName;
$('#submit').click(function(e) {
tName = $('#source option:selected').text();// name1
tName = tName.trim();
$.ajax({
url : 'someUrl',
type : 'GET',
cache : false,
success : function(d) {
var grid;
var searchString = "";
var data = [];
var columns = new Array();
var cols = d[0].columns;
var pkColNames = d[0].pkColNames;
for (var j=0; j< cols.length; j++) {
var key = {id: cols[j].colName, name: cols[j].colName, field: cols[j].colName, width: 200, sortable:true, editor: Slick.Editors.LongText};
columns[j] = key;
}
var options = {
editable: true,
enableAddRow: false,
enableCellNavigation: true,
asyncEditorLoading: false,
enableColumnReorder:true,
multiColumnSort: false,
autoEdit: false,
autoHeight: false
};
function myFilter(item, args) {
return true;// Let us return true all time ?
}
for (var i = 0; i < d.length; i++) {
var tempData = (data[i] = {});
var title = null;
var val = null;
for (var q = 0; q < d[i].columns.length; q++) {
title = d[i].columns[q].colName;
val = d[i].columns[q].colValue;
tempData[title] = val;
}
}
var dataView = new Slick.Data.DataView({ inlineFilters: true });
grid = new Slick.Grid("#myGrid", dataView, columns, options);
dataView.setPagingOptions({
pageSize: 25
});
var pager = new Slick.Controls.Pager(dataView, grid, $("#myPager"));
var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);
grid.setSelectionModel(new Slick.CellSelectionModel());
grid.onAddNewRow.subscribe(function(e, args) {
// Adding a new record is not yet decided.
});
grid.onCellChange.subscribe(function (e) {
var editedCellNo = arguments[1].cell;
var editedColName = grid.getColumns()[editedCellNo].field;
var newUpdatedValue= arguments[1].item[grid.getColumns()[editedCellNo].field];
var editedColType = "";
for (var cnt = 0; cnt < cols.length; cnt++) {
if (editedColName == cols[cnt].colName) {
editedColType = cols[cnt].colType;
break;
}
}
var pkKeyValue="";
for (var v=0; v <pkColNames.length;v++) {
for (var p=0; p<grid.getColumns().length; p++) {
if (pkColNames[v] == grid.getColumns()[p].field) {
var value = arguments[1].item[grid.getColumns()[p].field];
pkKeyValue += "{"+pkColNames[v] + '~' +getColDbType(grid.getColumns()[p].field) + ":"+value+"},";
break;
}
}
}
function getColDbType(colName) {
for (var c = 0; c < cols.length; c++) {
if (colName == cols[c].colName) {
return cols[c].colType;
}
}
}
pkKeyValue = pkKeyValue.substring(0, pkKeyValue.length-1);
$.ajax({
url: 'anotherUrl',
type:'GET',
dataType:'text',
success: function(f) {
bootbox.alert("Data updated successfully");
},
error: function() {
bootbox.alert("Error - updating data. Please ensure you are adding the data in right format.");
grid.invalidateAllRows();
grid.render();
}
});
});
grid.onClick.subscribe(function (e) {
//do-nothing
});
dataView.onRowsChanged.subscribe(function(e, args) {
grid.updateRowCount();
grid.invalidateRows(args.rows);
grid.render();
});
grid.onSort.subscribe(function(e, args) {
// args.multiColumnSort indicates whether or not this is a multi-column sort.
// If it is, args.sortCols will have an array of {sortCol:..., sortAsc:...} objects.
// If not, the sort column and direction will be in args.sortCol & args.sortAsc.
// We'll use a simple comparer function here.
var comparer = function(a, b) {
return a[args.sortCol.field] > b[args.sortCol.field];
}
// Delegate the sorting to DataView.
// This will fire the change events and update the grid.
dataView.sort(comparer, args.sortAsc);
});
// wire up the search textbox to apply the filter to the model
$("#txtSearch").keyup(function (e) {
console.log('Called...txtSearch');
Slick.GlobalEditorLock.cancelCurrentEdit();
// clear on Esc
if (e.which == 27) {
this.value = "";
}
searchString = this.value;
updateFilter();
});
function updateFilter() {
console.log("updateFilter");
dataView.setFilterArgs({
searchString: searchString
});
dataView.refresh();
}
dataView.beginUpdate();
dataView.setItems(data, pkColNames);
dataView.setFilterArgs({
searchString: searchString
});
dataView.setFilter(myFilter);
dataView.endUpdate();
},
error : function() {
bootbox.alert("Invalid user");
}
});
});
});
Your function myFilter() is always returning true so of course it will never work. The example that you looked at, was to filter something specific. I would recommend that you look at the following example to have a generic filter. From the example, simply type the text you are looking on a chosen column and look at the result... see example below (from SlickGrid examples).Using fixed header row for quick filters
In case you want a more in depth conditional filters ( > 10, <> 10, etc...), please take a look at my previous answer on how to make this kind of filtering possible, see my previous answer below:SlickGrid column type
Hope that helps you out

Kendo Ui Grid - dataItem.set() method not working properly

I have a grid with 4 columns name, age, collection, profit. But when I try to set a number column it's not reflecting on grid.
schema:
{
model:{
fields:{
name:{type:"string"},
age:{type:"number"},
collection: { type:"number", defaultValue:0.00},
profit: { type:"number", defaultValue:0.00}
}
}
}
This code works perfectly:
var grid = $("#grid").data("kendoGrid");
var data = grid.dataSource.at(0);
data.set("name", "John Doe");
But I want to update numeric column:
var grid = $("#grid").data("kendoGrid");
var data = grid.dataSource.at(0);
var collectionVal = 50000;
data.set("collection", collectionVal);
And it's not updating because the column is of type "number".
UPDATE:
pageable:
{
refresh : true,
pageSizes: true
},
edit: function(e)
{
$('input[name="age"]').blur(function()
{
mygrid = $("#grid").data("kendoGrid");
selectedRow = mygrid.select();
dataItem = mygrid.dataItem(selectedRow);
dataItem.collection = dataItem.age * dataItem.profit;
dataItem.set("collection", dataItem.collection);
});
}
Instead of updating collection in a blur handler defined in the edit, define a save event handler in your grid as follow:
pageable : {
refresh : true,
pageSizes: true
},
save : function (e) {
var profit = e.values.profit || e.model.profit;
var age = e.values.age || e.model.age;
this.dataSource.getByUid(e.model.uid).set("collection", age * profit);
}

Kendoui grid : Remember expanded detail grids on refresh [duplicate]

I have a scenario with grid within grid implemented using the detailInit method. Here when user makes edit, i do some calculations that will change the data in the both parent and child. and then to refresh data, i will call the datasource.read to render data. this works and the data is displayed, however any detail grid which are expanded will be collapsed, is there any way i can prevent this from happening.
To answer this and another question:
"I figured out how to set the data in the master from the child BUT, the
whole table collapses the child grids when anything is updated, this is a
very annoying behavior, is there anyway I can just update a field in
the master table without it collapsing all the child elements?
(basically, update the column, no mass table update)"
in another thread at: telerik
This is extremely annoying behavior of the Kendo Grid and a major bug. Since when does a person want the sub-grid to disappear and hide a change that was just made! But this isn't the only problem; the change function gets called a Fibonacci number of times, which will freeze the browser after a significant number of clicks. That being said, here is the solution that I have come up with:
In the main grid
$('#' + grid_id).kendoGrid({
width: 800,
...
detailExpand: function (e) {
var grid = $('#' + grid_id).data("kendoGrid");
var selItem = grid.select();
var eid = $(selItem).closest("tr.k-master-row").attr('data-uid')
if (contains(expandedItemIDs, eid) == false)
expandedItemIDs.push(eid);
},
detailCollapse: function (e) {
var grid = $('#' + grid_id).data("kendoGrid");
var selItem = grid.select();
var eid = $(selItem).closest("tr.k-master-row").attr('data-uid')
for (var i = 0; i < expandedItemIDs.length; i++)
if (expandedItemIDs[i] == eid)
gridDataMap.expandedItemIDs.splice(i, 1);
},
Unfortunately globally we have:
function subgridChange() {
var grid = $('#' + grid_id).data("kendoGrid");
for (var i = 0; i < expandedItemIDs.length; i++)
grid.expandRow("tr[data-uid='" + expandedItemIDs[i] + "']");
}
function contains(a, obj) {
for (var i = 0; i < a.length; i++)
if (a[i] === obj) return true;
return false;
}
expandedItemIDs = [];
Now the 'subgridChange()' function needs to be called every time a change is made to the subgrid.
The problem is that the number of times the change function in the subgrid gets called increases exponentially on each change call. The Kendo grid should be able to call a stop propagation function to prevent this, or at least give the programmer access to the event object so that the programmer can prevent the propagation. After being completely annoyed, all we have to do is to place the 'subgridChange()' function in the subgrid 'datasource' like so:
dataSource: function (e) {
var ds = new kendo.data.DataSource({
...
create: false,
schema: {
model: {
...
}
},
change: function (e) {
subgridChange();
}
});
return ds;
}
I also had to place the 'subgridChange()' function in the Add button function using something like this
$('<div id="' + gridID + '" data-bind="source: prodRegs" />').appendTo(e.detailCell).kendoGrid({
selectable: true,
...
toolbar: [{ template: "<a class='k-button addBtn' href='javascript://'><span class='k-icon k-add' ></span> Add Product and Region</a>" }]
});
$('.addBtn').click(function (event) {
...
subgridChange();
});
When a user selects a row, record the index of the selected row. Then after your data refresh, use the following code to expand a row
// get a reference to the grid widget
var grid = $("#grid").data("kendoGrid");
// expands first master row
grid.expandRow(grid.tbody.find(">tr.k-master-row:nth-child(1)"));
To expand different rows, just change the number in the nth-child() selector to the index of the row you wish to expand.
Actually all that is needed is the 'subgridChange()' function in the main grid 'dataBound' function:
$('#' + grid_id).kendoGrid({
...
dataBound: function (e) {
gridDataMap.subgridChange();
}
});
Different but similar solution that i used for same problem:
expandedItemIDs = [];
function onDataBound() {
//expand rows
for (var i = 0; i < expandedItemIDs.length; i++) {
var row = $(this.tbody).find("tr.k-master-row:eq(" + expandedItemIDs[i] + ")");
this.expandRow(row);
}
}
function onDetailExpand(e) {
//refresh the child grid when click expand
var grid = e.detailRow.find("[data-role=grid]").data("kendoGrid");
grid.dataSource.read();
//get index of expanded row
$(e.detailCell).text("inner content");
var row = $(e.masterRow).index(".k-master-row");
if (contains(expandedItemIDs, row) == false)
expandedItemIDs.push(row);
}
function onDetailCollapse(e) {
//on collapse minus this row from array
$(e.detailCell).text("inner content");
var row = $(e.masterRow).index(".k-master-row");
for (var i = 0; i < expandedItemIDs.length; i++)
if (expandedItemIDs[i] == row)
expandedItemIDs.splice(i, 1);
}
function contains(a, obj) {
for (var i = 0; i < a.length; i++)
if (a[i] === obj) return true;
return false;
}

Resources