kendoui grid custom group header with columns - kendo-ui

Does anyone know if there is a way to create a custom group header template that will allow columns to be shown with aggregate data by column in that group?
The grid component uses colspan and I want to control the entire rending of the group header template.
Example of modified HTML showing desired UI

With the current implementation of Kendo UI Grid only the aggregates from the grouped column can be displayed in the groupHeaderTemplate.
You can also check this post: http://www.telerik.com/forums/multiple-aggregates-in-groupheadertemplate
There isn't a recomended workaround.
What you can try is to calculate each sum you want.
{ field: "groupField", title: "groupField", groupHeaderTemplate: "#= getGroupInfo(data, count) #", hidden: true },
..
dataSource: {
data: gridData,
schema: { model: gridModel },
pageSize: 20,
group: { field: "groupField", aggregates: [{ field: "groupFieldId", aggregate: "count" }] }
},
And the getGroupInfoFunction:
function getGroupInfo(data, count) {
return '<div style="float: right;width: 95%;"><div style="float:left;"><span>Number of units in stock: ' + count + " Sum1: " + getSum1(data.value) + '</span></div> Sum2:' + getSum2(data.value) + '</div>';
};
GetSum1():
function getBatchStatus(id) {
var sum;
var data = $("#priceChangeTasks").data("kendoGrid").dataSource.data();
for (var i = 0; i < data.length; i++) {
if (data[i].groupFieldId== id) {
sum += data[i].yoursumfield1;
}
}
return sum;
};

Related

Filter Kendo Dropdownlist values within a kendo grid row based on value from another row

I have Kendo Grid, inside which I have dropdown input [editable]. Now I want to filter the values in dropdown based on value present in row next to it. For ex:
_________________________________________
Column 1 | Column 2 (this is a dropdown)
_________________________________________
A | Show only values relevant to A
__________________________________________
B | Show values relevant to B
_____________________________________________
C | Show values relevant to C
_________________________________________
you can do the following
On editing the row get the name from the first column
filter the second column based on the first column value
In the given sample below, I edited an existing sample provided by the Kendo UI for cascading dropdowns, so I wrote extra codes to get the Id of the first column, so in your case you can exclude the additional steps
The HTML needed
<div id="grid"></div>
The scripts needed
<script>
// array of all brands
var brands = [
{ brandId: 1, name: "Ford" },
{ brandId: 2, name: "BMW" }
];
// array of all models
var models = [
{ modelId: 1, name: "Explorer", brandId: 1},
{ modelId: 2, name: "Focus", brandId: 1},
{ modelId: 3, name: "X3", brandId: 2},
{ modelId: 4, name: "X5", brandId: 2}
];
$("#grid").kendoGrid({
dataSource: {
data: [
{ id: 1, brandId: 1, modelId: 2 }, // initial data item (Ford, Focus)
{ id: 2, brandId: 2, modelId: 3 } // initial data item (BMW, X3)
],
schema: {
model: {
id: "id",
fields: {
id: { editable: false }, // the id field is not editable
brandId: {editable: false}
}
}
}
},
editable: "inline", // use inline mode so both dropdownlists are visible (required for cascading)
columns: [
{ field: "id" },
{
// the brandId column
title: "Brand",
field: "brandId", // bound to the brandId field
template: "#= brandName(brandId) #", // the template shows the name corresponding to the brandId field
},
{
//The modelId column
title: "Model",
field: "modelId", // bound to the modelId field
template: "#= modelName(modelId) #", //the template shows the name corresponding to the modelId field
editor: function(container) { // use a dropdownlist as an editor
var input = $('<input id="modelId" name="modelId">');
input.appendTo(container);
input.kendoDropDownList({
dataTextField: "name",
dataValueField: "modelId",
//cascadeFrom: "brandId", // cascade from the brands dropdownlist
dataSource: filterModels() // bind it to the models array
}).appendTo(container);
}
},
{ command: "edit" }
]
});
function brandName(brandId) {
for (var i = 0; i < brands.length; i++) {
if (brands[i].brandId == brandId) {
return brands[i].name;
}
}
}
function brandId(brandName) {
for (var i = 0; i < brands.length; i++) {
if (brands[i].name == brandName) {
return brands[i].brandId;
}
}
}
function modelName(modelId) {
for (var i = 0; i < models.length; i++) {
if (models[i].modelId == modelId) {
return models[i].name;
}
}
}
// this function will be used by the drop down to filter the data based on the previous column value
function filterModels()
{
// bring the brand name from previous column
var brandName = $('#modelId').closest('td').prev('td').text();
// additional work in this sample to get the Id
var id = brandId(brandName);
// filter the data of the drop down list
var details= $.grep(models, function(n,i){
return n.brandId==id;
});
return details;
}
</script>
here a working demo
hope it will help you

Kendo UI Grid - Excel Export with hidden columns and custom formatting

I'm attempting to use the Grid component's built-in support for exporting to excel, applying custom cell formatting as shown in these Telerik docs:
http://docs.telerik.com/kendo-ui/controls/data-management/grid/how-to/excel/cell-format
The approach using hard-coded row / cell indexes in the export comes with a rather obvious issue when exporting a grid with a prior hidden column displayed - best way to reproduce is to refer to this jsfiddle:
https://jsfiddle.net/3anqpnqt/1/
Run fiddle
Click export to excel - observe custom number formatting
Unhide subcategory column (using column menu)
Click export to excel - observe custom number formatting on column 2 which is now 'subcategory'
With reference to this code in the fiddle:
$("#grid").kendoGrid({
toolbar: ["excel"],
excel: {
fileName: "Grid.xlsx",
filterable: true
},
columns: [
{ field: "productName" },
{ field: "category" },
{ field: "subcategory", hidden: true },
{ field: "unitPrice"}
],
dataSource: [
{ productName: "Tea", category: "Beverages", subcategory: "Bev1", unitPrice: 1.5 },
{ productName: "Coffee", category: "Beverages", subcategory: "Bev2", unitPrice: 5.332 },
{ productName: "Ham", category: "Food", subcategory: "Food1", unitPrice: -2.3455 },
{ productName: "Bread", category: "Food", subcategory: "Food2", unitPrice: 6 }
],
columnMenu: true,
excelExport: function(e) {
var sheet = e.workbook.sheets[0];
for (var rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
var row = sheet.rows[rowIndex];
var numericFormat = "#,##0.00;[Red](#,##0.00);-";
for (var cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {
var cell = row.cells[cellIndex];
if (row.type === "data") {
if (cellIndex == 2) { // how are we able to identify the column without using indexes?
cell.format = numericFormat;
cell.hAlign = "right";
}
}
}
}
}
});
What I need to be able to do is identify the cell as the 'unitPrice' and apply the format, but inspection of the object model within the excelExport handler doesn't give me any way to make this link. In my real application, I have several custom formats to apply (percentages, n0, n2 etc) so it's not as simple as going $.isNumeric(cell.value) or otherwise.
Update
I also need the solution to work with column / row groups, which generate additional header rows / columns in the Excel model.
It looks like row[0] is the header row, so you could try changing
if (cellIndex == 2) {
to
if (sheet.rows[0].cells[cellIndex].value == "unitPrice") {
EDIT:
Seems to work with column group: https://jsfiddle.net/dwosrs0x/
Update:
The object model for worksheet is not the most clear. The first row does seem to be a "master" header row in the various scenarios that I looked at. Here is something that seems to work if unitPrice is not in a grouping. If unitPrice is in a grouping, then something more complicated involving the group header (row[1]) might be possible. The puzzle is to find out what position the desired column will eventually occupy.
var header = sheet.rows[0];
var upIndex = -1;
var upFound = false;
for (var cellIndex = 0; cellIndex < header.cells.length; cellIndex++) {
if ('colSpan' in header.cells[cellIndex])
upIndex = upIndex + header.cells[cellIndex].colSpan;
else
upIndex = upIndex + 1;
if (header.cells[cellIndex].value == "unitPrice") { // wot we want
upFound = true;
break;
}
}
for (var rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
var row = sheet.rows[rowIndex];
if (row.type === "data" && upFound) {
var cell = row.cells[upIndex];
cell.format = numericFormat;
cell.hAlign = "right";
}
}
fiddle with groups - https://jsfiddle.net/dwosrs0x/4/
fiddle with straightforward grid (to prove it still works) - https://jsfiddle.net/gde4nr0y/1/
This definitely has the whiff of "bodge" about it.

Kendo UI grid number column with template won't filter

I created a Kendo UI grid with two columns.
One is just a number called num0.
the other is is called num1 and it's data is created from num0 through a
template.
The filter on num0 works find.
The filter on num1 shows up and you can use it but
no matches are found. ie: filter on num1 and select "Is equal" and enter "2",
then click "Filter"
and grid is emptied when it should have shown the 1st record.
Also, I made the num0 column editable and the num1 column not editable.
I would like num1 column to change if num0 is edited.
I think it has something to do with the "template" that I am using
to fill num1 column.
What do I need to do to fix this so the filter works?
Thanks
http://jsfiddle.net/elbarto99/acyxekgx/
$(document).ready(function()
{
// Define the datasource for the grid.
var dsNums = new kendo.data.DataSource({
// NOTE: I don't want a num1: data field set to static values.
// I would like one that is set from "num0 + 1" and when num0 data is edited
// num1 would be updated to "num0 + 1"
data: [
{ num0: 1 },
{ num0: 2 },
{ num0: 3 },
{ num0: 4 },
],
schema:
{
model:
{
id: "myGridID",
fields:
{
num0: { type: "number" },
num1: { type: "number", editable: false },
}
}
}
});
// Create the grid.
var _grid = $("#grid").kendoGrid({
dataSource: dsNums,
filterable: { extra: false },
editable: true,
columns: [
{ field: "num0" , title: "Num 0" , width: "90px", },
// Add 1 to num0 and display in num1 column
// Note: A filter shows up and is for numbers but doesn't work
// I think it doesn't work because I am using a template.
//
// What do I need to do to make the filter for column num1 work like it does for num0?
{ field: "num1" , title: "Num 1 - Filter shows up but doesn't find matchs. :-(" , width: "90px", template: "#= num0 + 1 #", },
],
}).data("kendoGrid");
});
num1 value is not part of the data so filter will not filter by it. Filters work at datasource level and not presentation.
What you might do is computing that same value on schema.parse function. Something like:
parse: function(d) {
$.each(d, function(idx, elem) {
elem.num1 = elem.num0 + 1;
});
return d;
}
Your JSFiddle modified here: http://jsfiddle.net/OnaBai/acyxekgx/2/
Thanks OnaBai:
I modified your jfiddle
and add some editable settings so num0 column is editable and num1 column is not editable.
Is there a way to make num1's data and presentation get updated to num0 + 1 if num0 is edited?
ie: num0 changed to 11, num1's data gets changed to num0+1 or 12,
and filter on num1 to find 12 will list row 1.
Also, make the presentation of num1 set to 12 so the user can see the change.
http://jsfiddle.net/elbarto99/acyxekgx/
// Define the datasource for the grid.
var dsNums = new kendo.data.DataSource({
// NOTE: I don't want a num1: data field set to static values.
// I would like one that is set from "num0 + 1" and when num0 data is edited
// num1 would be updated to "num0 + 1"
data: [
{ num0: 1 },
{ num0: 2 },
{ num0: 3 },
{ num0: 4 }
],
schema:
{
model:
{
id: "myGridID",
fields:
{
num0: { type: "number" },
num1: { type: "number", editable: false }
}
},
// This changes the data for num1 at load time but
// if the data in num0 is edited this doesn't change data for num1
// at edit time.
parse: function(d) {
$.each(d, function(idx, elem) {
elem.num1 = elem.num0 + 1;
});
return d;
}
}
});
// Create the grid.
var _grid = $("#grid").kendoGrid({
dataSource: dsNums,
filterable: { extra: false },
editable: true,
columns: [
{ field: "num0", title: "Num 0", width: "90px" },
{ field: "num1", title: "Num 1", width: "90px" }
]
}).data("kendoGrid");

How can I optimize datasource for Kendo UI Combobox with 5000 items?

In my test -> http://jsfiddle.net/olragon/642c4/12/, KendoUI Combobox cannot run with 5000 items, how can I make it work without calling severside data source or this is limit of KendoUI?
HTML
<h3>T-shirt Fabric</h3>
<input id="fabric" placeholder="Select fabric..." />
JS
/**
* Returns a random integer between min and max
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
$(document).ready(function() {
var superData = []
, data = [
{ text: "Cotton", value: "1" },
{ text: "Polyester", value: "2" },
{ text: "Cotton/Polyester", value: "3" },
{ text: "Rib Knit", value: "4" }
];
for(var _i=0; _i<5000; _i++) {
var randomEntry = data[getRandomInt(0,data.length-1)];
randomEntry.text += '-' + _i;
randomEntry.value += _i;
superData.push(randomEntry);
}
// create ComboBox from input HTML element
$("#fabric").kendoComboBox({
dataTextField: "text",
dataValueField: "value",
dataSource: superData,
filter: "contains",
suggest: true,
index: 3
});
});
Update
Fiddle link was updated.
Virtual scrolling and paging for Combobox was not yet supported by KendoUI
The problem is not in Kendo UI ComboBox but in your loop. Did you check what it does (not what you want it to do)? I would say that there is an error since data[getRandomInt(0,data.length-1)] does not return a new element but a reference so you are appending "_i" to the same 5 elements many times building up a very long string.
Try this instead:
for (var _i = 0; _i < 5000; _i++) {
var randomEntry = data[getRandomInt(0, data.length - 1)];
var newEntry = {
text: randomEntry.text + '-' + _i,
value : randomEntry.value += _i
};
superData.push(newEntry);
}
Check the modified version of the Fiddle here: http://jsfiddle.net/OnaBai/642c4/14/

Highlight the sorted column

I'm firing the databound event but I'm not sure what do do from there.
The links here lead to generic docs:
http://www.kendoui.com/forums/ui/grid/highlight-sorted-column.aspx
Does anyone have a simple example of highlighting the current sorted column?
The idea is as follows:
Handle the dataBound event of the grid.
Get the current sort expression of the data source using its sort method.
Find the grid column which is bound to the sorted field. Iterate over the grid columns field.
Highlight the table cells which correspond to the column index. Use the tbody field of the grid.
Here is a sample implementation:
<div id="grid"></div>
<script>
$("#grid").kendoGrid({
dataSource: [
{ name: "Jane Doe", age: 30 },
{ name: "Jane Doe", age: 33 }
],
sortable: true,
dataBound: function() {
var columns = this.columns;
var sort = this.dataSource.sort()[0];
var sortedIndex = -1;
if (sort) {
for (var i = 0; i < columns.length; i++) {
if (columns[i].field == sort.field) {
sortedIndex = i;
break;
}
}
}
if (sortedIndex >= 0) {
this.tbody
.find("tr")
.find("td:eq(" + sortedIndex + ")")
.css( { background: "#a0b0c0" } );
}
}
});
</script>
And a live demo: http://jsbin.com/ixahid/1/edit

Resources