KendoUI ObservableArray children being clobbered by KendoUI treeView - javascript

Backstory
I'm using AngularJS/KendoUI and using angular-kendo-ui as a the 'bridge' between the two. I'm using Kendo for it's treeview component and this piece is a client requirement.
What I need to accomplish is
1. draw the tree menu from data provided by a service
2. periodically check each element in this data, and update a 'disabled' prop
3. redraw elements in the treeview based on the results from the above step.
Assumptions
1. If I want to be able to update the kendo tree view, then I need to use Kendo's observeables
2. I may be using Kendo's ObservableArray incorrectly here.
The problem
If I create a new ObservableArray like so
var things = new kendo.data.ObservableArray([{
text: "Parent 1",
items: [{text: "Child 1"}, {text: "Child 2"}, {text: "Child 3"}]
}])
things be logged to the console and the structure is intact.
However, once the treeview is instantiated with this data, further logging of things to the console show that the children (items) are no longer present. It is very hard to iterate over and update children if they don't exist!
Plunker here http://plnkr.co/edit/qJpIvK?p=info, if you view the 'script.js' file and open the console, you should be able to see my issue.
here is the code
HTML
<div ng-app="MyApp">
<div ng-controller="TreeController">
<div kendo-tree-view k-options="thingsOptions"></div>
</div>
</div>
JS
var app = angular.module("MyApp", ["kendo.directives"]);
app.controller('TreeController', function($scope, $timeout) {
var things = new kendo.data.ObservableArray([{
text: "Parent 1",
items: [{
text: "Child 1"
}, {
text: "Child 2"
}, {
text: "Child 3"
}]
}, {
text: "Parent 2",
items: [{
text: "Child 1"
}, {
text: "Child 2"
}, {
text: "Child 3"
}]
}]);
// should have 3 items
console.log('preTreeView init', things[1].items);
$scope.thingsOptions = {
dataSource: things
};
$timeout(function() {
// the 3 items expected are gone, why?
console.log('postTreeView init', things[1].items);
}, 1000);
});
Is this a misuse of ObservableArray and if so, what is the correct approach?

Internally, the TreeView widget turns your ObservableArray into a kendo.data.HierarchicalDataSource http://docs.telerik.com/kendo-ui/api/framework/hierarchicaldatasource which moves each of the children into DataSource objects of their own.
You can navigate them afterward like this:
var treeViewWidget = $(".k-treeview").data("kendoTreeView");
var dataSource = treeViewWidget.dataSource; // this is a HierachicalDataSource
var parents = dataSource.data(); // Parent1 and Parent2
var parent1 = parents[0];
var doesParent1HaveChildren = parent1.hasChildren; // true
var childrenDataSource = parent1.children; // this is a HierarchicalDataSource
var child1 = childrenDataSource.data()[0]; // this is {text: "Child 1"}

Related

How can i add text in "$cordovaLocalNotification.schedule" for multiple ngCordova local notification dynamically?

Following is the way ngCordova docs shows how to add multiple local notifications
cordova.plugins.notification.local.schedule([{
id: 1,
text: "Multi Notification 1",
sound: isAndroid ? 'file://sound.mp3' : 'file://beep.caf',
at: dateObject,
autoCancel: true
},{
id: 2,
title: "Local Notification Example",
text: "Multi Notification 2",
at: dateObject,
autoCancel: true
}]);
I am iterating data coming from database so I have dynamic "id" and "date object". I ran it in a loop but only last notification gets scheduled even when ids are different so i found that i need to pass array of objects like shown above in "cordova.plugins.notification.local.schedule" to get it done but i don't know how to do it dynamically.
Please help i need to submit my project and this is stuck.
services.js
for(var i in TestTimeTable)
{
var notificationDate = new Date(TestTimeTable[i].year, TestTimeTable[i].month, TestTimeTable[i].day, TestTimeTable[i].hour, TestTimeTable[i].minute, 0, 0);
var notificationID = i + ref.getAuth().uid;
$cordovaLocalNotification.schedule({
id: notificationID,
title: 'Feedback Reminder',
text: 'Please Provide Lecture Feedback',
at: notificationDate,
autoCancel: true
}).then(function (result) {
});
}
cordova.plugins.notification.local.on("click", function (notification, state) {
$state.go('courses');
}, this)
});
It works now, problem was that notification ID (var notificationID = i + ref.getAuth().uid;) was not numeric. Thanks

Backbone Marionette Composite View Rendering Template

I'm trying to render a list with a Marionette CompositeView. I am not sure why the rendered list just has an item displaying the word result. I was expecting the first item to display Level 1.
Here is a fiddle to my current code: http://jsfiddle.net/16L1hen4/
Here is my JS, template, and data:
JavaScript:
var App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '#main'
});
var TreeModel = Backbone.Model.extend({
});
var TreeCollection = Backbone.Collection.extend({
model: TreeModel,
url: 'https://api.mongolab.com/api/1/databases/backbone-tree/collections/tree?apiKey=somekey'
});
var TreeView = Backbone.Marionette.CompositeView.extend({
initialize: function() {
console.log(this.collection);
},
tagName: 'ul',
template: _.template( $('#tree-template').html() )
});
var treeCollection = new TreeCollection();
treeCollection.fetch().done(function () {
var treeView = new TreeView({collection: treeCollection});
App.mainRegion.show(treeView);
});
Template:
<div id="main"></div>
<script type="text/template" id="tree-template">
<li><%- name %></li>
</script>
JSON Data:
{
"_id": {
"$oid": "54adab80e4b0aa674b256836"
},
"name": "Level 1",
"children": [
{
"name": "Child 1 - Level 2",
"children": [
{
"name": "Jon - Level 3"
},
{
"name": "Mary - Level 3"
}
]
},
{
"name": "Child 2 - Level 2",
"children": [
{
"name": "Bill - Level 3"
}
]
}
]
}
Read the marrionnete docs a bit closer - you need a childView defined....
You are using a CompositeView to display a Collection, but you need to define a childView to render the models
var LeafView = Backbone.Marionette.ItemView.extend({
// ...
});
var TreeView = Backbone.Marionette.CollectionView.extend({
childView: LeafView
})
here is an updated fiddle. http://jsfiddle.net/6ok1rptq/
Now the "result" showing in the html, without being familiar with the underscore source, I believe this is caused by the fact that the data given to the template is null, and a quick look at the source of underscore shows that it is using with
http://underscorejs.org/docs/underscore.html#section-148
"If a variable is not specified, place data values in local scope."
Meaning that the template can't find a "name" variable, and will instead look it up in the global scope (window)
Result is just the name of the jsfiddle iframe containing the result of the fiddle
<iframe name="result" ...>
I didn't test this, but I assume that the error lies with the fact that you didn't define a Marionette Itemview on the CompositeView.
The logical structure is to pass the Compositeview a collection as you did in the question, and the models will be rendered in separate itemviews.
In the itemview you can call:
this.model.get("property");
To access the properties from within the view.

Dynamically Creating Menu Structure using Knockout

I have a requirement to display menus and submenus but I have to populate the structure using a service response.
Below is the sample response I am getting from the service.
{name: "Item A",
url: "url of Item A",
title: "sometitle",
children: [{
name: "Child1 of A",
url: "url of Child1 of A",
title: "sometitle",
children: [{
name: "Grandchild of A",
url: "url of Grandchild of A",
title: "sometitle",
children: [{
name: "Grand Grand child of A",
url: "url of Grand Grand child of A",
title: "sometitle",
children: []
}]
}]
}]
},
{name: "Item B",
url: "url of Item B",
title: "sometitle",
children: []
},
{
name: "Item C",
url: "url of Item C",
title: "sometitle",
children: []
}
All the parent nodes Item A, Item B, Item c are displayed as menu buttons,with children as submenus. I have no information on the depth of the children.
Service can have any number of parents and any level of children nodes.
So,at runtime I have to create the menu structure.
Can i achieve the same using pure javascript ui/li tags? I want to create ui, li tags dynamically ,using a recursive function, which gives me a similar tree structure as shown in the response, Any pointer?
Thanks
Tani
I've faced this requirement myself, I'll present my solution:
I defined a Knockout template to render one item. This will be used to render the first 'tier' of items in your tree-like datastructure. The 'magic' is that the template will render the item's children, using the template itself. So the idea is basically a 'recursive template'. (Sorry if my explanation is a bit vague, the code below should make it clear.)
The template could look like this (suppose you store the service response in an array called items):
<script type="text/html" id="treeItem">
<li class="item">
<ul data-bind="template: { name: 'treeItem', foreach: children }"></ul> // Magic is in this line
</li>
</script>
Consume the template for the first tier of items:
<ul data-bind="template: { name: 'treeItem', foreach: items }"></ul>
Here is a Fiddle demonstrating the solution: http://jsfiddle.net/xsjxc8jd/
Edit: And it didn't even require observables :)

Angular $http.get

I'm trying to show all lists and the tasks associated with each list. In my controller I have:
$http.get('api/list/').success(function (data) {
$scope.lists = data;
$scope.tasks = data[0].Task;
});
This works for the first item but of course data[0].Task needs to be dynamic. The problem I'm having is that this is being called once for each list. I tried using a variable but it gets reset to it's original value. I've also tried using a callback but no luck. I'm not sure what I'm overlooking or if I'm going about it all wrong.
Your best bet is to wrap the http.get in a factory and let it return new representations of your Lists that have the tasks in them. This way you get new references and it won't overwrite your existing objects. Essentially, you want the http.get to return new List objects in its success resolution.
After that, the controller gets the promise resolution, takes the new list object, and binds it into something thats on the scope. This will filter through to the rest of the page and let you preserve existing lists/tasks for the life of the page.
Your GET api/list/ request you probably return something like this:
[
{
"id": 1,
"name": "List #1",
"tasks": [
{
"id": 1,
"name": "Task #1 on List #1"
},
{
"id": 2,
"name": "Task #2 on List #1"
},
{
"id": 3,
"name": "Task #3 on List #1"
}
]
},
{
"id": 2,
"name": "List #2",
"tasks": [
{
"id": 1,
"name": "Task #1 on List #2"
},
{
"id": 2,
"name": "Task #2 on List #2"
},
{
"id": 3,
"name": "Task #3 on List #2"
}
]
}
]
This is assuming that you always want to return the associated tasks in an api/list/ command.
You then only need to call this once every time you want to refresh all lists and all tasks.
You should have a single controller which is bound to a view, in which your $http.get is called. It should set $scope.lists = data on success.
In your view you simply need two nested ng-repeat tags. For example, you could use unordered lists:
<div ng-controller="ListsController">
<ul>
<li ng-repeat="list in lists">
<ul>
<li ng-repeat="task in list.tasks">
</li>
</ul>
</li>
</ul>
</div>
I haven't used angular but I'm pretty sure this is all you need to do. A single AJAX call will populate a <li> element for each list, with nested <li> elements for each task belonging to that list.
If each list has a task and you want a list of them you can do this:
$scope.tasks = data.map(function(obj){return obj.task;})
map creates an array based on what the function returns for each list.

KendoUI TreeView Dynamic JSON

I'm attempting to use the KendoUI by Telerik and get a treeview to bind to dynamic JSON from a generic handler.
In my generic handler, I'm using Newtonsoft.Json to convert a List to my JSON results, which works just great and even works with a different KendoUI control (charts).
Here is what I have as far as the javascript to build the treeview:
var treeSource = new kendo.data.DataSource({
transport: {
read: {
url: "Services/CategoryHandler.ashx",
dataType: "json",
contentType: "application/json; charset=utf-8",
type: "GET"
}
}
});
$("#treeview").kendoTreeView({
dataSource: treeSource
});
Here is a shortened example of the returned JSON:
[
{
"text":"Node 1",
"expanded":true,
"items":null
},
{
"text":"Node 2",
"expanded":true,
"items":null
}
]
"items" will be sub collections in the tree.
When I add the items directly to the datasource such as:
var treeview = $("#treeview").kendoTreeView({
dataSource: [
{ text: "Item 1", expanded: true, items: [
{ text: "Item 1.1" },
{ text: "Item 1.2" },
{ text: "Item 1.3" }
] },
{ text: "Item 2", items: [
{ text: "Item 2.1" },
{ text: "Item 2.2" },
{ text: "Item 2.3" }
] },
{ text: "Item 3" }
]
})
It works just fine. It just does not work when I call a service which writes out the JSON, and what I mean by it does not work, is no data shows up, it is blank.
Any thoughts to what I might be missing or guidance to how I can verify my data is even being returned from the service and even filling my DataSource properly?
Thanks
IMPORTANT As November 8th, 2012 KendoUI already supports it.
The Kendo TreeView does not support binding to a data source yet. The good news is that this is in the plans and will be implemented soon (next release).
It works for me with a trick. I am using the dynamic ViewBag with Json serialized at the controller and therefore, nodes are being drawn great.
My issue is that the events don't seem to work ok. For instance I want to catch the onDrop and rise an alert to show the actual values of such node, and instead it displays the text for ALL nodes. This is driving me crazy by the way.
This is my code, hope can help someone.
function onDrop(e) {
alert(treeView.text(e.sourceNode));
}
A Template must be assigned in order to work:
template: "<span rel='#= item.Id #'> #=item.text #</span>",

Categories

Resources