I need to access the column name dynamically in Kendo Grid template.
Code:
$("#grid").kendoGrid({
dataSource: [
{ Quantity: 2 , Amount: 650},
{ Quantity: 0, Amount: 0 },
{ Quantity: 1, Amount: 500 },
{ Quantity: 4, Amount: 1047 }
],
sortable: true,
columns: [
{
field: "Quantity",
template: function (dataItem) {
if (dataItem.Quantity == '0') {
return "--";
} else {
return dataItem.Quantity;
}
}
},
{
field: "Amount",
template: function (dataItem) {
if (dataItem.Amount == '0') {
return "--";
} else {
return dataItem.Amount;
}
}
}
]
});
Here inside the "columns -> template", I need to access the column thru variable instead of hardcoding it. How can I do that? Because in real life I will be having dynamic columns populated into dataSource and I will construct the columns array inside the for loop. Please help.
Please access this JSBIN: http://jsbin.com/egoneWe/1/edit
From what I understand, you build the columns array using something like:
var Definition = [
{ field: "Quantity" },
{ field: "Amount" }
];
var columns = [];
$.each(Definition, function (idx, item) {
columns.push({
field : item.field,
template: function (dataItem) {
...;
}
})
});
$("#grid").kendoGrid({
dataSource: data,
sortable : true,
columns : columns
});
Right? And the problem is that you want to use the same template function for several (all) columns instead of having to rewrite many.
If so, what you can do is:
var Definition = [
{ field: "Quantity" },
{ field: "Amount" }
];
var columns = [];
$.each(Definition, function (idx, item) {
columns.push({
field : item.field,
template: function (dataItem) {
return commonTemplateFunction(dataItem, item.field);
}
})
});
What I use in the columns array (columns definition for the Grid) is a function that receives two arguments: the dataItem for the row and the field's name being edited.
Then, I define the template function as:
function commonTemplateFunction(dataItem, field) {
if (dataItem[field] == '0') {
return "--";
} else {
return dataItem[field];
}
}
And your modified code is here : http://jsbin.com/egoneWe/3/edit
So, despite I cannot guess the column name, I can do the trick using the columns initiator.
Related
I'm trying to keep the filter value into KendoGrid and reuse it on relaod.
I find some code sample but doesn't working. I used getOptions to store values into localStorage. It's working. I have values into localStorage["kendo-grid-options"]. On reload, value appears into filters on header grid but data don't load. Error in the consoel is :
[! - SessionID: q0pbq0zsol3mjsxtd5mlendu, PageInstanceID: d11a8e2e-d716-43a0-8f4e-679eb87ad167, DateTime: 04/20/2022 20:53:10.894] Message: Uncaught
TypeError: Cannot read properties of undefined (reading 'data')
Impossible to find solution. If somebody has en idea... :)
My code is the following
function LoadSampleQualityControlPlanGridSummary(control,params) {
control.dataSource = new kendo.data.DataSource({ transport: {
read: function (options) {
GetDsBySp("sp_HMI_GetSampleControlPlanList", params, options.success);} }, schema: { model: {
id: "qm_spec_id" }, fields: {
qm_spec_desc: {
type: "string"
},
plan_name: {
type: "string"
} } } }); }
function InitSampleQualityControlPlanSummaryGrid(control) {
control.columns = [ { field: "qm_spec_name", title:
"Name") }, { field: "qm_spec_desc", title: "description")
}, { field: "plan_name", title: "Plan", } ]; }
//On load
_controls.SampleControlPlanSummary = control.findByXmlNode("GSQCP");
_controls.$SampleControlPlanSummary = $(_controls.SampleControlPlanSummary.domElement).data("kendoGrid");
InitSampleQualityControlPlanSummaryGrid(_controls.SampleControlPlanSummary);
var options = localStorage["kendo-grid-options"];
if (options) {
var parsedOptions = JSON.parse(options);
_controls.$SampleControlPlanSummary.setOptions(parsedOptions); _controls.$SampleControlPlanSummary.setDataSource(gridData);
} LoadSampleQualityControlPlanGridSummary(_controls.SampleControlPlanSummary,
paramControl);
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
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");
What I Need
I would like to sort my grid/store by the Parent field, but because the Parent field that is fetched is an object, it fails to fetch any records when I put a sorter based on the Parent property. Even if I add a sorter function, it is not called. I am using a rallygrid, not sure if that makes a difference
sorters: [{
property: 'Parent',
direction: 'DESC',
sorterFn: function(one, two) {
console.log('one',one);
console.log('two',two); // console never shows these
return -1;
}
}]
What I have tried
To get around displaying the object, I have added a renderer function to the Parent column. I tried adding a doSort to the column, and that function is called, but sorting the store does not call my sorterFn, it only uses the property and direction (similar to the console.log() that fails to run above)
Here is an example of a custom App that works properly. The key is setting the default storeConfig of remoteSort to false!
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
App = this;
Rally.data.ModelFactory.getModel({
type: 'PortfolioItem/Feature',
success: function(model) {
App.add({
xtype: 'rallygrid',
id : 'grid',
model: model,
columnCfgs: [
'FormattedID',
'Name',
{dataIndex: 'Parent', name: 'Parent',
doSort: function(state) {
var ds = this.up('grid').getStore();
var field = this.getSortParam();
console.log('field',field);
ds.sort({
property: field,
direction: state,
sorterFn: function(v1, v2){
v1 = v1.get(field);
v2 = v2.get(field);
console.log('v1',v1);
console.log('v2',v2);
if (!v1 && !v2) {
return 0;
} else if (!v2) {
return 1;
} else if (!v1) {
return -1;
}
return v1.Name.localeCompare(v2.Name);
}
});
},
renderer: function(value, meta, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
return record.data.Name;
}
}
}
],
storeConfig: {
remoteSort: false
}
});
}
});
}
});
I have this treeview wich can have a variable number of children (some nodes can have up to 3 generations of children, some may have only one etc)
What I'm trying to do is expand a certain node when the treeview is loaded. And I have 2 problems:
1) I can't find an event/callback so that I know when the treeview is ready
2) The expand function doesn't always work ( I'll explain )
This is my treeview:
function InitializeTreeview() {
var Children_Merchants = {
transport: {
read: {
url: function (options) {
return kendo.format(websiteRootUrl + '/Merchants/Merchants/?hasParents={0}', hasParent);
}
}
},
schema: {
model: {
model: {
id: "ID",
hasChildren: true,
children: Children_Merchants
}
}
}
};
var Brandowners = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: kendo.format(websiteRootUrl + '/Merchants/GetBrandowners?databaseID={0}', selectedDatabaseID)
}
},
//change: ExpandNode, - if I call expand node like this, it works.
schema: {
model: {
id: "ID",
hasChildren: true,
children: Children_Merchants
}
}
});
$('#treeview').kendoTreeView({
dataSource: Brandowners,
animation: {
collapse: {
duration: 200,
effects: "fadeOut"
},
expand: {
duration: 200,
effects: "fadeIn"
}
},
dataTextField: "Name",
complete: function () { alert('ok'); },
//dataBound : ExpandNode,
select: OnSelect,
expand: CheckIfHasParent
}).data('kendoTreeView');
}
function ExpandNode() {
var treeview;
treeview = $("#treeview").data("kendoTreeView");
var nodeToExpand = treeview.findByText('Adam'); //dummy txt, will have from parameter
treeview.expand(nodeToExpand);
}
The databind works ok, my controllers get called, everything's fine.
So what I tried is hook up the ExpandNode function to a click of a button. The function gets called but nothing happens. BUT if I hook it up to the change event of the parents datasource, it works. Another interesting thing is that the select works so if I replace treeview.expand(...) with treeview.select(...), it works on the click.
So my questions are:
1) What event should I use for loadEnd ( or smth like that ) - so I won't have to bind the function to button click (it's still ok but I preffer on load ended) - P.S. I tried all the ones I found on the kendo forums,like: change, requestEnd, success, dataBound and they don't work. I tried sending the JSON with the property "expanded" set to TRUE, for the node in question, but that only modifies the arrow to show like it's opened, but it doesn't call the controller and load the children.
2) Do you know why ExpandNode works only when binded to the change event? - the most important question to me.
3) If you have suggestions, or have I done something wrong in the initialiation of the treeview, please tell me.
I've copied your code with some free interpretations and the answer your questions is:
What event should I use for loadEnd => dataBound
Do you know why ExpandNode works only when binded to the change event? => No, it works without binding it to change event. If it does not then there is something else in your code.
Suggestions => There is some information missing about your code that might make the difference with what I've implemented.
What is CheckIfHasParent? => I have implemented it as a function that actually does nothing.
What is hasParent? => I've ignored it.
The code as I write it:
$(document).ready(function () {
function InitializeTreeview() {
var Children_Merchants = {
transport: {
read: function (op) {
var id = op.data.ID;
var data = [];
for (var i = 0; i < 10; i++) {
var aux = id * 100 + i;
data.push({ Name: "Name-" + aux, ID: aux});
}
op.success(data);
}
},
schema : {
model: {
model: {
id : "ID",
hasChildren: true,
children : Children_Merchants
}
}
}
};
var Brandowners = new kendo.data.HierarchicalDataSource({
transport: {
read: function (op) {
op.success([
{"Name": "Adam", "ID": 1},
{"Name": "Benjamin", "ID": 2},
{"Name": "Caleb", "ID": 3},
{"Name": "Daniel", "ID": 4},
{"Name": "Ephraim", "ID": 5},
{"Name": "Frank", "ID": 6},
{"Name": "Gideon", "ID": 7}
])
}
},
//change: ExpandNode, - if I call expand node like this, it works.
schema : {
model: {
id : "ID",
hasChildren: true,
children : Children_Merchants
}
}
});
$('#treeview').kendoTreeView({
dataSource : Brandowners,
animation : {
collapse: {
duration: 200,
effects : "fadeOut"
},
expand : {
duration: 200,
effects : "fadeIn"
}
},
dataTextField: "Name",
dataBound : ExpandNode,
expand : CheckIfHasParent
}).data('kendoTreeView');
}
function ExpandNode() {
var treeview;
treeview = $("#treeview").data("kendoTreeView");
var nodeToExpand = treeview.findByText('Adam'); //dummy txt, will have from parameter
treeview.expand(nodeToExpand);
}
function CheckIfHasParent(e) {
}
InitializeTreeview();
});
and you can play with it here : http://jsfiddle.net/OnaBai/dSt2h/
$("#treeview").kendoTreeView({
animation: {
expand: true
},
dataSource: dataSource,
dataBound: function (e) {
var tv = $("#treeview").data("kendoTreeView");
if (tv != null) {
tv.expand(".k-item");
}
},
dataTextField: "test",
dataValueField: "id"
});
For anyone who may be interested:
function ExpandNode() {
var treeview;
var node1;
treeview = $("#treeview").data("kendoTreeView");
var node2;
var myURL = kendo.format(websiteRootUrl + '/Merchants/GetPathForSelectedNode?databaseID={0}&merchantID={1}&brandownerID={2}', selectedDatabaseID,MerID,BowID);
node1 = treeview.dataSource.get(BowID);
node = treeview.findByUid(node1.uid);
var uid = node1.uid;
node.find('span:first-child').trigger('click'); //expand 1st level
$.ajax( {
url: myURL,
dataType: "json",
contentType: 'application/json; charset=utf-8',
success: function(result)
{
var length = result.length;
var lastVal = 1;
for (var i = 1; i < length-1; i++) {
$("#treeview li[data-uid=\'" + uid + "\'] ul.k-group").waitUntilExists (function
() {
i = lastVal; // have to reinitialize i because waitUntilExist's callback will find the i incermented, over the needed value
lastVal++;
node2 = node1.children.get(result[i]);
node = treeview.findByUid(node2.uid);
uid = node2.uid;
node1 = node2;
if(lastVal <= length-1)
node.find('span:first-child').trigger('click'); // keep expanding
else
{
treeview.select(node); // just select last node
currentSelectedNode = node;
}
});
}
if(length == 2) //select 1st child
{
$("#treeview li[data-uid=\'" + uid + "\'] ul.k-group").waitUntilExists (function
() {
node2 = node1.children.get(result[i]);
node = treeview.findByUid(node2.uid);
uid = node2.uid;
node1 = node2;
treeview.select(node); // just select last node
currentSelectedNode = node;
});
}
}
});
}
This is my method. The for loop starts at 1 because the 1st element in my array is the 1st node ID - wich I've already expanded. the .waitUntilExists is Ryan Lester's method (I put a link in the comments above). Many thanks to my colleague, to you OnaBai and, of courese, to Ryan Lester. I hope this helps someone. Cheers
ypu can easily find the treeview is ready for expand by following code which are expanding all the treeview nodes you can also find it by checking perticular id or text
hopw, following example will help you
Ex:
$("#treeview").kendoTreeView({
animation: {
expand: true
},
dataSource: dataSource,
dataBound: function (e) {
var tv = $("#treeview").data("kendoTreeView");
if (tv != null) {
tv.expand(".k-item");
}
},
dataTextField: "test",
dataValueField: "id"
});