Kendo TreeView with remote datasource only populates the root elements - javascript

I am having difficulty in fully populating a Kendo TreeView with a remote datasource, although with a local datasource it works fine.
In short, the first sample below uses a local datasource. This all works perfectly:
// local datasource, works perfectly
var local = new kendo.data.HierarchicalDataSource({
data: [
{
"DeviceGroupId": 1,
"DeviceGroupName": "Superdeluxe Devices",
"Devices": [
{
"Id": 1000,
"Name": "My First Device"
},
{
"Id": 1001,
"Name": "My Second Device"
}
]
}
],
schema: {
model: {
children: "Devices"
}
}
});
// initialize - this works!
$("#list-of-devices").kendoTreeView({
dataSource: local,
dataTextField: ["DeviceGroupName", "Name"],
loadOnDemand: false
});
Again, the sample above works just fine. Now, the second sample below does not: it only populates the treeview's root element ("Superdeluxe Devices"). And it totally ignores the children.
// remote datasource
var remote = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "/api/devices/list", // <-- confirmed this works
dataType: "json",
contentType: "application/json"
},
schema: {
model: {
children: "Devices"
}
}
}
});
// initialize
$("#list-of-devices").kendoTreeView({
dataSource: remote, // the issue: only shows top level nodes
dataTextField: ["DeviceGroupName", "Name"],
loadOnDemand: false
});
So, the issue in the second sample is that only the top level nodes are shown, without any option to expand.
I have looked into the following:
The data in both datasources, local and remote, are identical (I copied the results from remote into local)
Enabled/disabling the loadOnDemand option, now setting it by default to 'false'
Mapping stuff through the schema.data and schema.parse functions to no effect
Looked into the both the HierarchicalDataSource API and the TreeView API, as well as the Binding to remote data demo
Looked into older UserVoice issue, which indicates that it's possible now to fully load and render a TreeView
Summarized, I can't seem to figure out why the local variant works perfectly - and the remote does not show the children. Any suggestions?

The problem is in your remote DataSource definition where you defined the schema.model as part of the transport and it is not. It should be:
var remote = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "list.json",
dataType: "json",
contentType: "application/json"
}
},
schema: {
model: {
children: "Devices"
}
}
});
schema is at the same level than transport.

Related

Kendo UI Grid Javascript datasource call to controller action

I'm having trouble binding my JavaScript kendo ui grid to model data from an action method. All the examples i see are mostly MVC wrappers and the JavaScript examples are all different and none seem to work for me.
Here is where i'm at below.
I did a generic test with static data that works.
var dataSource_Test = new kendo.data.DataSource({
data: [{ LeagueDetailGroupId: "15", GroupName: "Best Team 5"}]
});
Here is the datasource object im trying to create with the controller action:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "#Url.Action("LeagueDetailGroup_Read", "Configuration")?_leagueTypeId=" + leagueTypeId,
// i have tried all kinds of variants here, and not sure what to put
// my action method is returning json using kendo's DataSourceResult method
//contentType: "application/json",
type: "POST"
//dataType: "odata"
},
schema: {
data: "Data", // seen this in examples, dunno what it does
total: "Total", // seen this in examples, dunno what it does
model: {
id: "LeagueDetailGroupId",
fields: {
LeagueDetailGroupId: { editable: false, nullable: true },
GroupName: { validation: { required: true } }
}
}
},
// i seen this is an example from telerik but dont understand the use case for it
parameterMap: function (data, operation) {
// this prints no data before i even start so its a moot point configuring it from products to my stuff at this moment
// but not sure what todo here of if i need this anyways
console.log(data);
if (operation != "read") {
// post the products so the ASP.NET DefaultModelBinder will understand them
var result = {};
for (var i = 0; i < data.models.length; i++) {
var product = data.models[i];
for (var member in product) {
result["products[" + i + "]." + member] = product[member];
}
}
return result;
} else {
return JSON.stringify(data)
}
}
}
});
Here is the grid which works ok with the generic static datasouce object.
var grid = $("#leagueEdit_ldg_grid").kendoGrid({
dataSource: dataSource,
sortable: true,
pageable: true,
autobind: false,
//detailInit: leagueEdit_ldg_detailInit,
dataBound: function () {
this.expandRow(this.tbody.find("tr.k-master-row").first());
},
columns: [
{
field: "LeagueDetailGroupId",
title: "Group Id",
width: "110px"
},
{
field: "GroupName",
title: "Group Name",
width: "110px"
}
]
});
Delayed read, autobind set to false.
dataSource.read();
Here is my simplified Controller action. It runs and gets data, and works fine for my MVC wrapper grids.
[Route("LeagueDetailGroup_Read/{_leagueTypeId:int}")]
public ActionResult LeagueDetailGroup_Read([DataSourceRequest]DataSourceRequest request, int _leagueTypeId = -1)
{
DataSourceResult result =
_unitOfWork.FSMDataRepositories.LeagueDetailGroupRepository.Get(
ld => ld.LeagueTypeId == _leagueTypeId
)
.ToDataSourceResult(request,
ld => new LeagueDetailGroupViewModel
{
LeagueDetailGroupId = ld.LeagueDetailGroupId,
LeagueTypeId = ld.LeagueTypeId,
GroupName = ld.GroupName,
DateCreated = ld.DateCreated,
DateLastChanged = ld.DateLastChanged
}
);
// data looks fine here
return Json(result, JsonRequestBehavior.AllowGet);
}
Currently i'm getting this error:
Uncaught TypeError: e.slice is not a function
at init.success (kendo.all.js:6704)
at success (kendo.all.js:6637)
at Object.n.success (kendo.all.js:5616)
at i (jquery-3.1.1.min.js:2)
at Object.fireWith [as resolveWith] (jquery-3.1.1.min.js:2)
at A (jquery-3.1.1.min.js:4)
at XMLHttpRequest.<anonymous> (jquery-3.1.1.min.js:4)
It's hard to know without testing but let me know how this works.
Change your controller so that you are just returning a json string.
Also, try removing your schema and the parameter map, and set your dataType to json:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "#Url.Action("LeagueDetailGroup_Read", "Configuration")?_leagueTypeId=" + leagueTypeId,
dataType: "json"
}
}
});
For the grid I find simple json data does not usually need a schema/model defined. Kendo is super annoying and hard to debug. Let me know how it goes.
In my experience, an e.slice error happens when you have a record that has a null value in it somewhere. The kendo grid is not really smart enough to deal with this so you either have to make sure your datasource returns empty strings instead of nulls for string fields, or put a client template on the columns that translates a null into an empty string. It's possible that the kendo todatasourceresult made the problem come to light. Note that that is usually the last step before returning your dataset since it can modify the entity queries to give paging, so that you never query more than a single page of data (for ajax grids).

EXTJS Extending Ext.data.JsonStore

I'm an ExtJS (I'm using version 5.1) newbie and I'm trying to split a monolithic single file application in different files. I've moved a store outside in a separate file. This is the store in the separate file:
Ext.define("MT.store.MicroProfilerStore", {
extend: "Ext.data.JsonStore",
singleton : true,
model : 'MT.model.MicroProfilerModel',
storeId: "micro_profiler_store",
autoLoad: false,
proxy: {
type: 'ajax',
url: './backend/profiler.php',
reader: {
type: 'json',
rootProperty: 'answers'
}
}
});
If I use this file the ajax request is correct and I can see the reply but it looks like the store is ignoring the rootProperty and instead of having the array of answers in the store.getData() I have a single item array with the first value that is the entire response converted to javascript like:
[{success: 'true', answers: [{}, {}]}]
But If I create the store directly without subclassing using Ext.create("Ext.data.JsonStore", {...}) it's working!
The hack that I've found after a day of trying that allows me to keep a separate file for the store is this:
Ext.define("MT.store.MicroProfilerStore", function(){
Ext.require(['MT.model.MicroProfilerModel'], function(){
Ext.create("Ext.data.JsonStore", {
singleton : true,
model : 'MT.model.MicroProfilerModel',
storeId: "micro_profiler_store",
autoLoad: false,
proxy: {
type: 'ajax',
url: './backend/profiler.php',
reader: {
type: 'json',
rootProperty: 'answers'
}
}
});
});
return {};
});
Then I can get the store using StoreManger.lookup(). Ok it's working fine but the question is why ?
PS
I've already tried preloading the model before the store, explicity requiring the model and the store in many place It doesn't looks like a precedence error
Thanks for your help
We have many stores which could be made singleton, but it seems that singleton:true isn't part of ExtJS best practices.
If we need a "singleton store", which is like 90% of the time, we still make a normal store, but add that store to the stores array in Application.js, so that the instance is created before Application launch. What makes the store a singleton is a storeId, by which it is referenced from everywhere. All our singleton stores are defined using a special constructor/callParent construction, because we didn't get reader rootProperty to work otherwise:
Ext.define('MyApp.store.Directories',{
extend: 'Ext.data.Store',
storeId: 'DirectoryStore',
constructor: function() {
var me = this;
this.callParent([{
proxy: {
type: 'ajax',
headers:{'Accept':'application/json'},
noCache: true,
pageParam: false,
startParam: false,
limitParam: false,
extraParams: {
q: 'directory'
},
url: '../api/AddressBook',
reader: {
type: 'json',
rootProperty: 'data'
}
},
autoLoad: true
}]);
}
});
The special constructor/callParent part makes the difference here. We don't exactly know WHY it works, but it works - we copied that approach from Sencha Architect-generated code. If we now need that store's content anywhere, we do as follows:
xtype:'combo',
name:'Directory',
store:'DirectoryStore' // <- reference by storeId!
The storeId reference fails if we don't add the store to the stores array in Application.js, where we should keep a list of all "singleton" stores:
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
name: 'MyApp',
views: [
/* Allgemein */
...
],
controllers: [
'Configuration',
...
],
stores: [
'Directories',
...
]

Populating a grid using kendo js

I am working on a web app which needs to populate a grid with some data. I have a button wired with a onClick method which opens a new modal window for the grid to be displayed. I am using a jquery post call to the controller. However, I am unable to get the json data and assign it to my variable.
My code is as follows:
var grid_ds;
$.post('${ctx}/class/student/details?studentId=${student.studentId}', function(data){
}, 'json');
$('#student_grid').kendoGrid({
dataSource: grid_ds,
columns: [
{field: "studentName", title: "Student Name"},
{field: "studentClass", title: "Class"}
],
dataBound: function () {
emptyGrid($('#student_grid'));
}
}).data('kendoGrid');
My controller sends json back. I can see the data coming. How should I assign the json data to grid_ds and student_grid and make the values populate in the grid.
You could try using a kendo.data.DataSource with a custom transport function like so:
$('#student_grid').kendoGrid({
dataSource: dataSource = new kendo.data.DataSource({
transport: {
read: function (e) {
$.post('${ctx}/class/student/details?studentId=${student.studentId}', 'json')
.done(function (data) {
e.success(data);
});
}
}
}),
columns: [
{
field: "studentName",
title: "Student Name"
},
{
field: "studentClass",
title: "Class"
}
]});
I think the problem may be with how you're fetching the data. Since $.post is an ajax call operating out of band, grid_ds is most likely undefined when being passed to the .kendoGrid() function.
I wasn't able to locate the dataBound configuration property that you specify in your question in the kendo.ui.Grid. Do you happen to know where this configuration setting came from?

Sencha touch store - phantom data

I created a model like
Ext.define('MyApp.model.ContainerDetailsModel', {
extend: 'Ext.data.Model',
alias: 'model.ContainerDetailsModel',
config: {
fields: [
{
name: 'id',
allowNull: false,
type: 'string'
},
{
name: 'container_types_id',
type: 'string'
}
]
}
});
and a store like this
Ext.define('MyApp.store.ContainerDetailsStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.ContainerDetailsModel'
],
config: {
model: 'MyApp.model.ContainerDetailsModel',
storeId: 'ContainerDetailsStore',
proxy: {
type: 'ajax',
enablePagingParams: false,
url: 'hereIsServiceUrl',
reader: {
type: 'json'
}
}
}
});
Now somewhere in application I tried to get one record like:
var detailsStore = Ext.getStore("ContainerDetailsStore");
detailsStore.load();
var detailsRecord = detailsStore.last();
But it gaves me undefined. The json returned by service is ok, it use it in different place as source for list. I already tried to change allowNull to true, but there is no null id in source. I tried set types to 'int' with the same result.
So I have tried
console.log(detailsStore);
Result is like this (just important values):
Class {
...
loaded: true,
data: Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
...
},
...
}
In the same place
console.log(detailsStore.data);
returns (as it should):
Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
but (next line)
console.log(detailsStore.data.all);
returns
[]
And it's empty array. When i try any methods from the store it says the store is empty.
I wrote console.log() lines one after another - so for sure it doesn't change between them (I try it also in different order or combinations).
My browser is Google Chrome 23.0.1271.97 m
I use Sencha from https://extjs.cachefly.net/touch/sencha-touch-2.0.1.1/sencha-touch-all-debug.js
How can I take a record from that store?
store.load() Loads data into the Store via the configured proxy. This uses the Proxy to make an asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved instances into the Store and calling an optional callback if required. The method, however, returns before the datais fetched. Hence the callback function, to execute logic which manipulates the new data in the store.
Try,
detailsStore.load({
callback: function(records, operation, success) {
var detailsRecord = detailsStore.last();
},
scope: this
});

How to get data from extjs 4 store

Im stack with ext js 4 at the very beginning. Im trying to get the current user data when starting the application using store. But Im not getting any data from the store, even the store.count return 0.
I found many description how to create store, but not how to access the data in it. I managed to get the data using Ext ajax request, but i think would be better using store and i cant avoid them..
My model:
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: [
'id',
'username',
'email'
]
});
My store looks like:
Ext.define('MyApp.store.User.CurrentUser', {
extend: 'Ext.data.Store',
requires: 'MyApp.model.User',
model: 'MyApp.model.User',
autoLoad: true,
proxy: {
type: 'ajax',
method: 'POST',
url: Routing.generate('admin_profile'),
reader: {
type: 'json',
root: 'user'
}
}
});
The returned json:
{
"success":true,
"user":[{
"id":1,
"username":"r00t",
"email":"root#root.root"
}]
}
And the application:
Ext.application({
name: 'MyApp',
appFolder: '/bundles/myadmin/js/app',
models: ['MyApp.model.User'],
stores: ['MyApp.store.User.CurrentUser'],
//autoCreateViewport: true,
launch: function() {
var currentUser=Ext.create('MyApp.store.User.CurrentUser',{});
/*
Ext.Ajax.request({
url : Routing.generate('admin_profile'),
method: 'POST',
success: function(resp) {
var options = Ext.decode(resp.responseText).user;
Ext.each(options, function(op) {
var user = Ext.create('MyApp.model.User',{id: op.id,username:op.username,email:op.email});
setUser(user);
}
)}
});
*/
currentUser.load();
alert(currentUser.count());
}
});
The problem itself isn't that the store does not contain data, the problem is that the store load is asyncronous therefore when you count the store records, the store is actualy empty.
To 'fix' this, use the callback method of the store load.
currentUser.load({
scope : this,
callback: function(records, operation, success) {
//here the store has been loaded so you can use what functions you like
currentUser.count();
}
});
All the sencha examples have the proxies in the store, but you should actually put the proxy in the model, so that you can use the model.load method. the store inherits the model's proxy, and it all works as expected.
it looks like model.load hardcodes the id though (instead of using idProperty), and it always has to be an int, as far as I can tell.
good luck!

Categories

Resources