KendoUI, tweaking the recurrence editor - kendo-ui

With KendoUI 2013.3.1109
I am using KendoUI's scheduler
I am using a template for the reservation form, but via googling and perusing the forums, I read about re-using their recurrence form. I even figured out via experimenting that one could select which period options are available by, for instance, running:
$("#recurrenceEditor").kendoRecurrenceEditor(
{
frequencies: ["never", "daily", "weekly", "monthly"]
});
});
The code above will not load the 'yearly' option in the drop down.
There is no API documentation for kendoRecurrenceEditor on the website, but I was wondering if it is possible to tweak additional options, like removing the 'never' tag on when a recurrence should expire and so on.

So I initialize the Kendo recurrence editor:
$("#recurrenceEditor").kendoRecurrenceEditor({
change: function() {
onRecurrenceEditorChange();
}
});
Then I tweak what's visible inside #recurrenceEditor
var onRecurrenceEditorChange = function() {
var recurrenceKendoNumericTextBox = $('#recurrenceEditor .k-widget.k-numerictextbox.k-recur-count input[data-role="numerictextbox"]')
.data('kendoNumericTextBox');
if (recurrenceKendoNumericTextBox != null) {
var recurrenceEditorNeverEndOption = _container.find('#recurrenceEditor label:has(.k-recur-end-never)');
if (recurrenceEditorNeverEndOption != null)
recurrenceEditorNeverEndOption.hide();
recurrenceKendoNumericTextBox.max(10);
var recurrenceKendoDatePicker = _container.find('#recurrenceEditor .k-datepicker input[data-role="datepicker"]').data("kendoDatePicker");
if (recurrenceKendoDatePicker != null) {
var maxDate = window.moment().add('months', 2).toDate();
recurrenceKendoDatePicker.max(maxDate);
recurrenceKendoDatePicker.value(maxDate);
}
}
};
Then if you want to tweak the intervals, hack around it this way:
var recurrencePeriodKendoDropDownList = $('.k-widget.k-dropdown input[data-role="dropdownlist"]').data("kendoDropDownList");
var recurrencePeriodFilters = [
{
field: "value",
operator: "neq",
value: 'yearly'
}, {
field: "value",
operator: "neq",
value: 'monthly'
},
// if it's a newres, don't hide 'Never' option which matches to "",
{
field: "value",
operator: "neq",
value: someBoolConditionIhave ? "fake" : ""
}
];

Related

Kendo Grid filter using checkboxes and mutliple selections

I am using custom multi-select code to filter a column. Currently I can get it to filter based on one selection, but am unable to filter based on multiple values. I need the logic to read, if any of the selected checkboxes are checked, then show the selections in the grid. The way I have it written right now, its filtering each one, but if one of the selections is false, it deletes it from the grid even if one of the other selections are true.
var filter = dataSource.filter() || { logic: "or", filters: [] };
var fieldFilters = $.map(element.find(":checkbox:checked"), function (input) {
return {
field: field,
operator: "eq",
value: input.value
};
});
if (fieldFilters.length) {
removeFiltersForField(filter, field);
filter.filters.push({
logic: "or",
filters: fieldFilters
});
var filterType = filter.filters[0].filters;
if (filter.filters[0].filters.length > 1) {
var filterLogic = { logic: "or", filters: filter.filters };
dataSource.filter(filterLogic.filters[0]);
} else {
dataSource.filter(filterType); // This works, but its only one selection
}
}
I need it to return if any selections are true and ignore the ones that are false. Currently, it goes in order, so if the first selection is true, it shows it in the grid, but if the next one is false, then it removes it from the grid.
OK I was able to make it work doing this. If someone has a more efficient way to do it, add it here. For now, this works:
var multipleFilters = [];
if (filterType.length > 1) {
$(filterType).each(function (i, value) {
var simpleFilter = { field: value.field, operator: value.operator, value: value.value };
multipleFilters.push(simpleFilter);
})
if (multipleFilters == 2) {
dataSource.filter(multipleFilters[0] || multipleFilters[1]);
} else if (multipleFilters == 3) {
dataSource.filter(multipleFilters[0] || multipleFilters[1] || multipleFilters[2]);
} else {
dataSource.filter(multipleFilters[1] || multipleFilters[2] || multipleFilters[3]);
}
} else {
dataSource.filter(filterType);
}

How to filer Kendo grid with respect to column filter and searchbox text value

I have a Kendo grid and I already appy a column filter and I need to filter this result with a text box value I tried like
var sText = $("#searchBox").val();
if (sText.length > 0) {
var filterChild = [];
var filtOut = [];
var ds = $('#homeGridCustomer').data('kendoGrid').dataSource;
var curr_filters = ds.filter();
filterChild.push({ field: "Name", operator: "contains", value: sText });
filterChild.push({ field: "City", operator: "contains", value: sText });
filterChild.push({ field: "CustomerNo", operator: "contains", value: sText });
var filtParent = { filters: filterChild, logic: "or" };
if (curr_filters != undefined) {
filtOut.push(curr_filters);
}
filtOut.push(filtParent);
ds.filter({ filters: filtOut, logic: "and" });
but it didn't getting the filtered output, nothing is showing. can anyone help ? Thanks in advance
If you wish to apply multiple search filters to multiple columns in the dataSource based on the same input value and maintain the existing filters already applied (with the ability to clear the filters when nothing is entered in the search area), try using:
var ds = $("#grid").data("kendoGrid").dataSource;
var sText = $("#nameOfYourInput").val();
var filterToApply = ds.filter();
if(!filterToApply) {
// if not, setup new filter
filterToApply = {
logic: "and", // use OR here if you want to search for a value in either column instead of all columns
filters: []
}
}
var applyFilters = false;
// check to see if `sText` contains value before filtering (as filter will apply like `Name`/`City`/`CustomerNo` `contains` `null`/`undefined` otherwise)
if(sText) {
applyFilters = true;
filterToApply.filters.push({field: "foo", operator: "contains", value: sText});
filterToApply.filters.push({field: "bar", operator: "contains", value: sText});
}
if(applyFilters) {
ds.filter([filterToApply]);
}
else {
ds.filter([]);
}
I have attached a jsbin example for you to play about with which defaults to overwriting existing grid filters based on the new input value, and have included commented out code which can be used to build on top of existing filters. Hopefully you can get what you need from this.

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 grid resizable column width

The grid columns may be resizable. I want to store user-adjusted columns width and restore them when the next session starts.
The best way to store columns width I've found is the following:
var element = $('#grid').kendoGrid({
...
resizable: true,
columnResize: function(e) {
var state = {};
this.columns.every(function(c,i) {
state[c.field] = c.width;
return true;
});
var state_txt = JSON.stringify(state);
localStorage['profile_userprofile_grid_column_width'] = state_txt;
}
}
Now I want to restore column width saved in the previous user session. I can read columns width from the storage:
var state = JSON.parse(localStorage['profile_userprofile_grid_column_width']);
Does somebody know some elegant way to apply these values back to the grid if it is already created at this time? The resize handle does it internally, so it is possible, but the code doing it in the grid source is ugly.
You can trigger the columnResize event post initilisation as shown below
function grid_columnResize(e) {
// Put your code in here
console.log(e.column.field, e.newWidth, e.oldWidth);
}
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: [
{ name: "Jane Doe", age: 30 },
{ name: "John Doe", age: 33 }
],
resizable: true
});
var grid = $("#grid").data("kendoGrid");
grid.bind("columnResize", grid_columnResize);
Documentation
This is an old question, but here is what we have. Function handles column widths and groups.
var _updateResultsGridColumns = function(columns, groups) {
var kendoGrid = $resultsGrid.data("kendoGrid");
if (kendoGrid) {
kendoGrid.setOptions({
columns: columns,
});
var dataSource = kendoGrid.dataSource;
dataSource.group(groups);
kendoGrid.setDataSource(dataSource);
}
}

Kendo Treeview Expand Node

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"
});

Resources