Kendo.DropDownList changing datasource dynamically - drop-down-menu

I am a new user and have not been able to find an example demonstrating what I'm trying to accomplish.
I need to use the same Kendo.DropDownList in two different contexts, but must update one attribute [.Name("DisbursedTo")]. At first I used a hide/show approach with two separate ddl's. It worked, except that each ddl widget required a unique '.Name', so my updates to the model attribute were off. Using one ddl, I'm trying to dynamically change the ddl properties.
By default I load the ddl with 'Locations' data (this works fine). After initial load, I use a simple Radio Button group 'onclick' to switch to 'ADUsers', or back to 'Locations'.
cshtml
<label for="DisbursedTo">Disbursed To:</label>
#(Html.Kendo().DropDownList()
.Name("DisbursedTo")
.DataTextField("Name")
.DataValueField("LocationId")
.SelectedIndex(20)
.DataSource(dataSource => dataSource
.Read(read => read.Action("GetLocations", "Disbursement")) // Specify the action method and controller name
.ServerFiltering(true) // If true the DataSource will not filter the data on the client.
)
)
script
function OwnerTypeClick(ownerTypeValue) {
if (ownerTypeValue == "P") {
alert("calling DisbursedToADUsers");
DisbursedToADUsers();
}
else {
alert("calling DisbursedToLocations");
DisbursedToLocations();
}
}
function DisbursedToADUsers() {
var adUsersIntranetDataSource = new kendo.data.DataSource({
read: {
action: { "GetADUsersIntranet": "Disbursements" }
}
});
var ddl = $("#DisbursedTo").kendoDropDownList({
dataTextField: "displayName",
dataValueField: "EmployeeNumber",
dataSource: adUsersIntranetDataSource,
autoBind: true
});
ddl.dataSource.read();
}
function DisbursedToLocations() {
var locationsDataSource = new kendo.data.DataSource({
read: {
action: { "GetLocations": "Disbursements" }
}
});
var ddl = $("#DisbursedTo").kendoDropDownList({
dataTextField: "Name",
dataValueField: "LocationId",
dataSource: locationsDataSource,
autoBind: true
});
ddl.dataSource.read();
}
I'm getting the following error on the 'ddl.dataSource.read();' so I'm not getting my datasource changed/initialize properly.
0x800a138f - Microsoft JScript runtime error: Unable to get value of the property 'read': object is null or undefined
If anyone has done something similar, I'd greatly appreciate some assistance.

The provided code suggests that you are initializing new DropDownList widgets from the same HTML element every time, and also that new DataSources are created every time.
You can create the two different DataSources outside of the functions, and then in the functions bodies use the DropDownList setDataSource() method to switch between the two dataSources, and the setOptions() method to change the other options like dataTextField and dataValueField, e.g.:
Example

You need to use a Kendo DropDownListFor.

Related

How to apply filters to a kendo grid datasource on startup

I have a application that has a kendo grid.
I can filter the grid using several dropdownlists that are outside the grid.
When I click on search, I add filters to the datasource filter list. For example,
var dataSource = $("#grid").data("kendoGrid").dataSource;
var dataSourceFilterQuery = new Array();
if ($("#something").data("kendoDropDownList").value() !== null) {
dataSourceFilterQuery.push({ field: "something", operator: "IsGreaterThanOrEqualTo", value: ($("#something").data("kendoDropDownList").value()) });
}
dataSource.filter(dataSourceFilterQuery);
Then I get the results I want. It works.
I then have the possibility of saving the values of all the dropdownlists as one filter in localStorage.
const filtersObject = {
Something: whatever.value(),
...
};
this.storage.setItem("Filter", JSON.stringify(filtersObject));
When I restart the application, the dropdownlists are populated with whatever is in localStorage
const filter = JSON.parse(localStorage.getItem("Filter"));
$("#something").data("kendoDropDownList").value(filters.whatever || "");
}
The thing is, I wanted to add these filters, if they exist on localStorage, to the datasource when the application starts so that the user can see the results of the filter he saved when the applications starts and not have to click on search again.
So, what I want is to do apply this
var dataSource = $("#grid").data("kendoGrid").dataSource;
var dataSourceFilterQuery = new Array();
if ($("#something").data("kendoDropDownList").value() !== null) {
dataSourceFilterQuery.push({ field: "something", operator: "IsGreaterThanOrEqualTo", value: ($("#something").data("kendoDropDownList").value()) });
}
dataSource.filter(dataSourceFilterQuery);
before the grid is displayed.
Is this possible?
Tks in advance.
Configure the Grid with
autoBind: false
http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#configuration-autoBind
and when the page loads, call your filter setup, then trigger the grid load manually (via dataSource.read())

Kendo Grid: Keep custom popup open after save new record

I've got a custom popup editor template for my Kendo Grid which contains tabs. One of the tabs is to have a second Kendo Grid of records relating to the record being edited.
I'd like to be able to create a new record and immediately start adding the related records, without having to re-open the newly created record. Obviously, I have to first save the record in order for its ID to be generated.
I've managed to prevent the popup editor closing when new records are saved, but I think the popup window is no longer bound to the model at this point.
Is there a way I can rebind the window to the model so I can carry on editing and adding the related records?
Thanks
Edit: Here's the technique for keeping the editor open:
The grid's edit and save events:
edit: function(e){
var editWindow = this.editable.element.data("kendoWindow");
editWindow.bind("close", onWindowEditClose);
},
save: function(e){
if (e.model.isNew()) {
preventCloseOnSave = true;
} else {
preventCloseOnSave = false;
}
}
The onWindowEditClose:
var onWindowEditClose = function(e) {'
if (preventCloseOnSave) {
e.preventDefault();
preventCloseOnSave = false;
}
};
I ended up using a slightly clunky workaround, but other than a minor UI 'flash' it works okay.
The Grid has a rowTemplate, so I've added the record's ID field to the TR tags so I can find them by ID. I then have a function that runs on the complete event when a new record is created which finds the new row and immediately opens it:
var ds = new kendo.data.DataSource({
// ...
transport: {
create: {
url: '/url/to/create',
dataType: 'json',
type: 'post',
complete: recordCreated
}
});
function recordCreated(e) {
"use strict";
var id = e.responseJSON.data[0].id,
grid = $('#grid').data("kendoGrid"),
row = grid.tbody.find("tr[data-id='" + id + "']");
grid.editRow(row);
}
On a conceptual level, you could intercept the POST action that saves the record to the database and get the saved data on return. Note that your POST action must return the saved object (as is expected). You can hook into this event by using the requestEnd method of the Kendo UI Datasource object that supports your grid and bind the saved record to your edit window (as long as you have a reference to it).
var ds = new kendo.data.DataSource({
// ...
requestEnd: function (e) {
kendo.bind(editWindow, e.response); // bind the returned data to your edit window
}
});
The understanding of the kendo ui structure (which can be tedious at times) is important to getting anything done with it. The closing of the popup that allows inserting is done in the dataBinding event. Therefore, that is the place we need to prevent it from:
$("#yourgrid").kendoGrid({
dataSource: yourDataSource,
columns: [
{ field: "YouColumn", title: "YourTitle", ... },
...
]
.
.
.
editable: "popup",
dataBinding: function(e){
//this is the key to keeping the popup open
e.preventDefault();
},
save: function (e) {
//whatever you need to do here
}
.
.
.
});
Hope this helps someone.
//Houdini

KendoUI - Remote Databinding Fails within "kendoWindow"

I made this topic once, but the information I had was a bit hard to follow and I did not get much help, so I am trying again after spending the day making a JSBIN sample.
I have a situation where I am using KendoUI to make a view model, and also to make some items within it, and when you click on sub-items that are drawn, it opens up a KendoWindow to let you edit them more specifically.
However, there is a problem with the dataSource concept, I think. When I try to bind to a dataSource on my page it works fine; But when I try to bind a kendo control to a remote datasource within a rendered window, it refuses to fetch.
If I bind only to local data, hard coded data, it works; So I know the dropdownlist is working. But I really need to be able to bind to remote data.
I have prepared a JSBIN to show this behavior (or lack thereof)
JSBIN EXAMPLE
Any help would be greatly appreciated. To see the behavior, click on the button to Create Socket Rail, then use the NumericTextBox to increase the size to any number higher than 0, then click on one of the drawn boxes.
You need to create the kendoDropDownList in the kendoWindow.activate event (or at least bind the DataSource there). Adapted from your code, this will work:
kendoWindowWidget = function (options) {
// extend the settings options so that we can take
// explicit configuration from the widget caller.
var settings = $.extend({
resizable: false,
modal: true,
viewable: true,
visible: false,
width: "450px",
height: "450px",
activate: function () {
var myDataSource = new kendo.data.DataSource({
transport: {
read: {
dataType: "json",
url: "http://jsbin.com/UYEbOXi/3/js"
}
}
});
widgets.windows.sockets.type = $('#socket-type').kendoDropDownList({
dataTextField: "Name",
dataValueField: "Id",
dataSource: myDataSource
}).data("kendoDropDownList");
}
}, options);
var $window = $("<div id='kendow-editor-window'/>")
.kendoWindow(settings)
.data("kendoWindow");
$window.databind = function (e) {
kendo.bind($window.element, e);
$window.open().center();
};
// return the created combo box
return $window;
};
Adapted JSBin (I removed a bunch of things to make it easier to manage):
http://jsbin.com/uMuFewI/3/edit

How to change columns set of kendo grid dynamically

I am trying to change the columns collection of my Kendo grid in the below way.
var grid = $("#grid").data("kendoGrid");
$http.get('/api/GetGridColumns')
.success(function (data) {
grid.columns = data;
})
.error(function (data) {
console.log(data);
});
This is changing the column collection but not reflecting immediately in my grid. But when I try to perform some actions in the grid (like grouping), then my new column set is appearing.
Please let me know how can I achieve this.
Regards,
Dilip Kumar
You can do it by setting the KendoUI datasource, destroy the grid, and rebuild it
$("#load").click(function () {
var grid = $("#grid").data("kendoGrid");
var dataSource = grid.dataSource;
$.ajax({
url: "/Home/Load",
success: function (state) {
state = JSON.parse(state);
var options = grid.options;
options.columns = state.columns;
options.dataSource.page = state.page;
options.dataSource.pageSize = state.pageSize;
options.dataSource.sort = state.sort;
options.dataSource.filter = state.filter;
options.dataSource.group = state.group;
grid.destroy();
$("#grid")
.empty()
.kendoGrid(options);
}
});
});
here you can just do this :
var options = grid.options;
options.columns = state.columns;
where you can retrieve the columns in a session or in a db
This jsfiddle - Kendo UI grid dynamic columns can help you - using kendo.observable.
var columns = data;
var configuration = {
editable: true,
sortable: true,
scrollable: false,
columns: columns //set the columns here
};
var grid = $("#grid").kendoGrid(configuration).data("kendoGrid");
kendo.bind($('#example'), viewModel); //viewModel will be data as in jsfiddle
For the ones who are using Kendo and Angular together, here is a solution that worked for me:
The idea is to use the k-rebind directive. From the docs:
Widget Update upon Option Changes
You can update a widget from controller. Use the special k-rebind attribute to create a widget which automatically updates when some scope variable changes. This option will destroy the original widget and will recreate it using the changed options.
Apart from setting the array of columns in the GridOptions as we normally do, we have to hold a reference to it:
vm.gridOptions = { ... };
vm.gridColumns = [{...}, ... ,{...}];
vm.gridOptions.columns = vm.gridColumns;
and then pass that variable to the k-rebind directive:
<div kendo-grid="vm.grid" options="vm.gridOptions" k-rebind="vm.gridColumns">
</div>
And that's it when you are binding the grid to remote data (OData in my case). Now you can add or remove elements to/from the array of columns. The grid is going to query for the data again after it is recreated.
When binding the Grid to local data (local array of objects), we have to somehow postpone the binding of the data until the widget is recreated. What worked for me (maybe there is a cleaner solution to this) is to use the $timeout service:
vm.gridColumns.push({ ... });
vm.$timeout(function () {
vm.gridOptions.dataSource.data(vm.myArrayOfObjects);
}, 0);
This has been tested using AngularJS v1.5.0 and Kendo UI v2016.1.226.
I'm use this code for change columns dynamic:
kendo.data.binders.widget.columns = kendo.data.Binder.extend({
refresh: function () {
var value = this.bindings["columns"].get();
this.element.setOptions({ columns: value.toJSON });
this.element._columns(value.toJSON());
this.element._templates();
this.element.thead.empty();
this.element._thead();
this.element._renderContent(this.element.dataSource.view());
}
});
Weddin
Refresh your grid
.success(function (data) {
grid.columns = data;
grid.refresh();
})
Here is what i use
var columns = [];//add the columns here
var grid = $('#grid').data('kendoGrid');
grid.setOptions({ columns: columns });
grid._columns(columns);
grid._templates();
grid.thead.empty();
grid._thead();
grid._renderContent(grid.dataSource.view());
I think a solution for what you are asking is to call the equivalent remote DataSource.read() method inside of the function. This is what I used to change the number of columns dynamically for local js data.
$("#numOfValues").change(function () {
var columnsConfig = [];
columnsConfig.push({ field: "item", title: "Metric" });
// Dynamically assign number of value columns
for (var i = 1; i <= $(this).val(); i++) {
columnsConfig.push({ field: ("value" + i), title: ("201" + i) });
}
columnsConfig.push({ field: "target", title: "Target" });
columnsConfig.push({ command: "destroy", title: "" });
$("#grid").data("kendoGrid").setOptions({
columns: columnsConfig
});
columnDataSource.read(); // This is what reloads the data
});
Refresh the grid
$('#GridName').data('kendoGrid').dataSource.read();
$('#GridName').data('kendoGrid').refresh();
Instead of looping through all the elements. we can remove all the data in the grid by using a single statement
$("#Grid").data('kendoGrid').dataSource.data([]);
If your grid is simple and you don't need to configure special column-specific settings, then you can simply omit the columns argument, as suggested in the API reference.
Use autogenerated columns (i.e. do not set any column settings)
... and ....
If this [column] setting is not specified the grid will create a column for every field of the data item.
var newDataSource = new kendo.data.DataSource({data: dataSource}); $("#grid").data("kendoGrid").setDataSource(newDataSource);
$("#grid").data("kendoGrid").dataSource.read();
After fighting this for a day and seeing hints in this thread that Kendo had simplified this problem, I discovered you can just use setOptions with a single property.
.success(function (data) {
grid.setOptions({
columns: data,
});
})
Grid Set Options

Using durandal with jaydata and kendoui

I created a new VS2012 project using the hottowel template, which in return uses durandal, knockout and breeze.
I want to use jaydata instead of breeze and for the ui layer I want to use the excellent asKendoDataSource() functionality to power a kendoui grid.
I followed all the instructions to make kendoui work well with durandal. This is fine.
I have a model in which I get the jaydata entities and run asKendoDataSource() on it. My view is an MVVM declared kendoui grid with its source property set to the viewmodel's property that contains a reference to the asKendoDataSource().
In the knockout world the viewModel property would be an empty entities = ko.observableArray() which would then would be initialized by using entities(values) when the data service returns.
I need to mimic this such that I have a viewModel property that is an empty kendo datasource which then is initialized by the asKendoDataSource() conversion when the data comes back from jaydata. This way the mvvm kendo grid is bound initially to the empty datasource and then receives its items when the asKendoDataSource() is called.
This is all because the model - viewModel binding in durandal is asynchronous and there needs to be a placeholder property in the viewModel from the very beginning, which then, after the viewModel's activate() method promise is resolved, gets updated with the bound data and in return powers the DOM that the viewModel is bound to.
I can't figure out how to mimic the knockoutjs practice of an empty observable array which is bound to the dom and then (the same exact reference) gets initialized and populates the dom. There seems to be no way to create an empty kendo datasource which then is re-initialized by the asKendoDataSource() method. Reassigning the viewModel property to the new data source doesn't work because the kendo grid is bound to the original reference.
This is my airport view:
<section>
<h2 class="page-title" data-bind="text: title"></h2>
<div id="airportGrid" data-kendo-role="grid" data-kendo-sortable="true" data-kendo-pageable="true" data-kendo-page-size="25" data-kendo-editable="true" data-kendo-columns='["Id", "Abbrev", "Name"]' data-kendo-bind="source: airports"></div>
</section>
This is my datacontext:
define([
'durandal/system',
'services/logger'],
function (system, logger) {
var getAirports = function (airportsObservable) {
$data.Entity.extend("Airport", {
Id: { type: "int", key: true, computed: true },
Abbrev: { type: String, required: true, maxLength: 200 },
Name: { type: String, required: true, maxLength: 512 }
});
$data.EntityContext.extend("JumpSeatDatabase", {
Airports: { type: $data.EntitySet, elementType: Airport }
});
var airportDB = new AirportDatabase('http://localhost:2663/odata');
var deferred = Q.defer();
airportDB.onReady(function () {
deferred.resolve(airportDB.Airports);
});
return deferred.promise;
}
var datacontext = {
getAirports: getAirports
};
return datacontext;
function log(msg, data, showToast) {
logger.log(msg, data, system.getModuleId(datacontext), showToast);
}
function logError(msg, error) {
logger.logError(msg, error, system.getModuleId(datacontext), true);
}
//#endregion
});
This is my airport viewmodel:
define(['services/datacontext', 'durandal/plugins/router'],
function (datacontext, router) {
var airports = null;// = kendo.data.ObservableArray([]);
var activate = function () {
var airportRes = datacontext.getAirports();
return airportRes.then(function (airp) {
vm.airports = airp.asKendoDataSource();
});
};
var deactivate = function() {
//airports([]);
};
var viewAttached = function (view) {
//using this type of reach in to the viewModel is considered bad practice in durandal
//$('#airportGrid').kendoGrid({
// dataSource: airports.asKendoDataSource({ pageSize: 10 }),
// filterable: true,
// sortable: true,
// pageable: true,
// height: 500,
// columns: ['Id', 'Abbrev', 'Name']
//});
//kendo.init($("#container"));
kendo.bind(view, vm);//this should eventually go away the recommended ViewModelBinder code in main.js is not firing for me
};
var vm = {
activate: activate,
deactivate: deactivate,
airports: airports,
title: 'Airports',
viewAttached: viewAttached
};
return vm;
});
One last issue that I am seeing:
It seems to me that an MVVM declared kendoui grid, bound to the view model through data-kendo-bind={source: airports)" where airports is a property of the viewmodel that was created through entities.asKendoDataSource() does not work. Somehow the grid does not show the data. Is there something extra that needs to be done?
Thanks
My best guess is that this is a timing issue, where the Grid is binding to vm.airports while it is still null, then vm.airports = airp.asKendoDataSource(); is called after it is already bound? Perhaps try something like:
return airportRes.then(function (airp) {
vm.airports.data(airp.asKendoDataSource().data());
});

Resources