Dojo - Dijit.Tree - Updating Tree - javascript

I created a simple tree based on a TreeStoreModel which is backed by ItemFileWriteStore.
I tried updating my tree by deleting and adding items to the store as below, but could not.
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.Tree");
dojo.addOnLoad(function () {
var tmpData = [{
"name" : "Dell",
"type" : "business",
"businessid" : "1",
"projectid" : "1",
"submenu" : [{
"name" : "OTP",
"type" : "product",
"productid" : "100"
}
]
}
];
var tmpData1 = [{
"name" : "Lenovo",
"type" : "business",
"businessid" : "1",
"projectid" : "1",
"submenu" : [{
"name" : "OTP",
"type" : "product",
"productid" : "100"
}
]
}
];
var store = new dojo.data.ItemFileWriteStore({
data : {
label : 'name',
items : tmpData
}
});
var treeModel = new dijit.tree.TreeStoreModel({
store : store,
query : {
type : 'business'
},
childrenAttrs : ["submenu"]
});
var divTestTree = dojo.create("div", null, dojo.body(), "first");
var mytree = new dijit.Tree({
model : treeModel
},
divTestTree);
/* Tree is created at this point */
/* Delete the item from the store, for some reason tempData is being reset*/
store.deleteItem(tmpData[0]);
/* save */
store.save();
/* Tree shows up no more at this point */
/* Try adding new item to the store */
store.newItem(tmpData1[0]);
/* save */
store.save();
/*nothing happens! */
});
I followed the lead from here, I must be missing something very trivial here. Please help.

Taken from that page
How do I refresh a Tree from the store?
This isn’t supported. The store needs to notify the tree of any changes to the data. Currently this is really only supported (out of the box) by dojo.data.ItemFileWriteStore, as setting up a client-server dojo.data source where the server notifies the client whenever the data has changed is quite complicated, and beyond the scope of dojo, which is a client-only solution.
The only way to update the tree is to re-draw it again :(

For anyone coming here looking for a solution the problem, 'I suspect there is a bug' is the only answer I got in the forum, so may be this is a bug - goo.gl/M7xg7

Related

Firebase data structuring - accessing jobIDs for each user

In my database, I currently have two kinds of objects, users and jobs. I am already storing userIDs in jobs. Do I also need to store jobIDs in each user?
A typical user:
"-JqzUjcOfddBNd_HtjKb" : {
"contact" : {
"-JqzWcIyD77ZwatEKALp" : {
"email" : "someguy#yahoo.com"
},
"-JqzWrtyni3ZGOKooNF7" : {
"email" : "someguy#outlook.com"
}
},
"country" : "234",
"cv" : "https://linktourl.com",
"dateAdded" : 1433436879708,
"ethnicity" : "0",
"firstName" : "John",
"lastName" : "Smith",
"notes" : {
"-JqzhvtNcueUsPr8xwh8" : {
"date" : 1433440599702,
"user" : "iwrotethisnote#example.com",
"value" : "interested in job; need to interview"
}
},
"roles" : [ true ]
},
And a typical job:
"-Jqz5mOr-DmLcxmTVRPi" : {
"age" : [ "2" ],
"city" : "0",
"clientID" : "-Jqz7goZC76vl94VT0dq",
"dateModified" : 1433431226687,
"longDesc" : "Teacher should have experience",
"notes" : {
"-Jqz6SO74OJOESwOVfkG" : {
"date" : 1433430513294,
"notevalue" : "bill spoke with her",
"userid" : "name#gmail.com"
}
},
"schedule" : "Evening or weekend",
"status" : "needDetail",
"subjects" : {
"15" : true,
"42" : true
},
"title" : "She wants a native speaker"
},
As you can see, jobs have a field for clientID, which is a foreign key (so to speak) of a user's id. When I access a user's information, I want to know those jobs that they are associated with (i.e. for which they have supplied their client ID). How to do this in Firebase?
Should I:
Update both objects, and keep an array of jobIDs in the client object?
Query all jobs, then pass in those that have the user's ID as the client ID. Something like:
// user controller
var jobs = [];
jobsRef.$on('value', function(snapshot) {
snapshot.val().forEach(function(job) {
if (job.clientID = $scope.userID) {
jobs.push(job);
}
}
}
Option 1 makes the data redundant (which I guess is ok, because of the emphasis on denormalization), but it also makes it more likely to become out of sync, for example if one of the two updates I would be making fails.
Option 2 seems like it would run a lot slower.
You can use equalTo() of firebase query
var jobsRef = new Firebase();
jobsRef.orderByChild("clientID").equalTo($scope.userID)
.on("value", function(snapshot) {
console.log(snapshot.key());
});
For more info, please check out Query.equalTo()

How can I create a dynamic list of routes from JSON?

I have a JSON file containing information for a tile based navigation app which uses the Router. Each tile could be a link directly to an external application, or it could contain subtiles which are displayed when the tile is clicked. Each of these could have their own subtiles, and so on. The JSON will eventually be delivered by an OData service so the app needs to dynamically create the navigation as it may change.
How can I implement the Router to have the URL looking like #tile1/tile1-1/tile1-1-3 which would indicate the user clicked on the first tile, which went to a screen where they clicked on the first tile there, followed by another screen on which they clicked the third tile? That route would, when coming from a bookmark, load the screen with subtiles from the tile1-1-3 node from the JSON.
The names 'tile1-1-3' etc are only to help visualise the position of the tile for this example. In the real version the names won't indicate the position in the tree, they will be more like #MyApps/MyApprovalApps.
I have a recursive function which crawls through every node and generates an individual route, but I'm unsure how to add the dynamic pattern like {tile}/{subtile}/{subtile} and also the parent route which I think will be needed to navigate between the levels properly.
I have a Home.view.xml which displays the top level tiles, and a Page1.view.xml for the rest of the levels of subtiles. Is this correct? How can I create the views dynamically if not?
Hopefully my goal is clear, I can elaborate more if needed.
Recursive function which creates the routes:
createRoutes: function(aData, oRouter){
for(var i=0; i<aData.length; i++){
oRouter.addRoute({name: aData[i].id,
pattern: aData[i].title,
view: "Page1"}); //parent?
if(aData[i].subtiles.length > 0){ // has subtiles
this.createRoutes(aData[i].subtiles, oRouter);
}
}
}
JSON:
{
"TilesCollection" : [
{
"id" : "tile1",
"title" : "tile1",
"target" : "#",
"subtiles" : [
{
"id" : "tile1-1",
"title" : "tile1--1",
"target" : "#",
"subtiles" : []
}
]
},
{
"id" : "tile2",
"title" : "tile2",
"target" : "#",
"subtiles" : [
{
"id" : "tile2-1",
"title" : "tile2--1",
"target" : "#",
"subtiles" : []
},
{
"id" : "tile2-2",
"title" : "tile2--2",
"target" : "#",
"subtiles" : []
},
{
"id" : "tile2-3",
"title" : "tile2--3",
"target" : "#",
"subtiles" : [
{
"id" : "tile2-3-1",
"title" : "tile2--3--1",
"target" : "#",
"subtiles" : []
},
{
"id" : "tile2-3-2",
"title" : "tile2--3--2",
"target" : "#",
"subtiles" : []
}
]
}
]
},
{
"id" : "tile3",
"title" : "tile3",
"target" : "#",
"subtiles" : []
},
{
"id" : "tile4",
"title" : "tile4",
"target" : "#",
"subtiles" : [
{
"id" : "tile4-1",
"title" : "tile4--1",
"target" : "#",
"subtiles" : []
}
]
}
]
}
How about this?
createRoutes: function(aData, oRouter, sParentPattern, iViewLevel) {
iViewLevel = iViewLevel || 0;
for (var i=0; i<aData.length; i++) {
var sPattern = sParentPattern ? sParentPattern +"/"+ aData[i].title : aData[i].title;
oRouter.addRoute({
name: aData[i].id,
pattern: sPattern,
view: "Page1",
viewLevel : iViewLevel
});
if (aData[i].subtiles.length > 0) {
this.createRoutes(aData[i].subtiles, oRouter, sPattern, iViewLevel+1);
}
}
}
In this example you just use the pattern to build the parent-child relationship just as you suggested.
If I understand you correctly you're asking how can you represent th clicking route as a string, whcih you can pass as prt of a URL ?
Referring to the tile IDs...
You could pass the text in as a JS array of objects I guess (ie include this JSON as part of the URL) :
a.b.com/xyz?route=[{"tile1-1",{"tile1-1"}},{"tile2",{"tile2-3"}}]
meaning they clicked tile1 -> tile1-1 -> tile2 -> tile2-3
Alternatively if the Ids are potentially secure or something, you could pass it by index no. as it's an aray :
a.b.com/xyz?route=[{0,{0}},{0,{2}}]
Then eval the passed string to turn it directly into Javascript object.
Or if you're concerned about people hacking, write a routine to interpret it.
(same clicking as above) - this relies on the tile arrangement never changing though.

Accessing nested JSON objects

I'm building an Angular App and also using angular translate as it needs to be in dual languages.
I've seem to have created my JSON properly (ran it through a checker), but when I try to access items within the JSON object beyond the first level, it returns undefined.
For instance, my JSON within the angular translations is this:
$translateProvider.translations('en', {
"SEARCH": {
"SEARCH" : "Recherce",
"ABILITY" : "Abilities",
"MANAGEMENT" : "Management Competencies",
"PERSONAL" : "Personal Suitability"
},
"ABILITIES": {
"TITLE" : "Test Title here",
"ADVISORY": {
"TITLE" : "Advisory Skills",
"QUESTIONS": [
{
"TYPE" : "A",
"LEVEL" : "45",
"DESCRIPTION" : "Can you tell me how awesome you are"
},
{
"TYPE" : "B",
"LEVEL" : "100",
"DESCRIPTION" : "Tell me about your wicked project"
}
]
}
},
"HEADLINE": "Oh No!",
"SUB_HEADLINE": "Looks like you are not amazing"
});
And to begin accessing the data in the JSON object, I do
list = $translateProvider.translations('en');
Now, when outputting items in the console to see if they work I do this:
console.log(list);
var getTitle = list.HEADLINE;
var getSearch = list.SEARCH.ABILITY;
console.log(getSearch);
console.log(getTitle);
This is where it gets odd.
The 'list' returns the JSON array I specified
Getting the HEADLINE returns Oh No!
But getting list.SEARCH.ABILITY returns an undefined
What gives!? I haven't event tried to access the stuff I really want in the really nested array "ABILITIES"
Keep in mind that Angular Translate uses the format {{ 'ABILITIES.ADVISORY.TITLE' | translate }} to output the JSON onto the HTML page
try list.SEARCH["ABILITY"].value

manage neo4j cross relationship in d3.js

I start recently to work with Neo4j database and i'm trying to display a graph using d3js (i'm new with it too!).
For my test i used the movie example data include in neo4j.
Using JQuery ajax and neo4j REST API, i find a way to make it more or less work.
But currently i can't make an actor link to several movie (or i duplicate them!).
here is currently my Cypher request:
match (a)-[r]->(m) RETURN {id: id(m), name: m.title}, collect({name : a.name, id: id(a)})
and the answer i get look like this:
{
"columns" : [ "{id: id(m), name: m.title}", "collect({name : a.name, id: id(a)})" ],
"data" :
[
[
{ "id" : 3, "name" : "The Matrix Reloaded" },
[
{ "id" : 5, "name" : "Keanu Reeves" },
{ "id" : 6, "name" : "Laurence Fishburne" },
{ "id" : 7, "name" : "Carrie-Anne Moss" }
]
],
[
{ "id" : 4, "name" : "The Matrix Revolutions" },
[
{ "id" : 5, "name" : "Keanu Reeves" },
{ "id" : 6, "name" : "Laurence Fishburne" },
{ "id" : 7, "name" : "Carrie-Anne Moss" }
]
],
[
{ "id" : 2, "name" : "The Matrix" },
[
{ "id" : 5, "name" : "Keanu Reeves" },
{ "id" : 6, "name" : "Laurence Fishburne" },
{ "id" : 7, "name" : "Carrie-Anne Moss" }
]
]
]
}
So i'm thinking of 2 workarounds : either i find a way in d3 to do it (but i have a real hard time to understand d3js for this) or i change my cypher request to get the relationship in a different way.
i can of course make a huge workaround in javascript but my objective is to keep the code as much effective as possible (at the end i want to use it to get a lot of data).
i use the example here : http://bl.ocks.org/mbostock/1093130
where i modify the flatten function like this (and some other minor change) :
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [], i = 0;
root.data.forEach(function(l) {
var childrenlist = [];
l[1].forEach(function(actor) {
var ac = { name: actor.name, id: actor.id };
childrenlist.push(ac);
nodes.push(ac);
});
var movie = { id: l[0].id, name: l[0].name, children: childrenlist };
nodes.push(movie);
});
return nodes;
}
/*! end of flatten */
So ! since i have a hard time with d3js, i'm looking a way to make my cypher request to give me the relationship info in a different way. more like this example : http://bl.ocks.org/mbostock/4062045
i'm really stuck because i don't know how to build my cypher request!
i'm looking for a way to get the relationship source and destination node id and the node list but i don't know how to do both!
i want to mix this 2 requests:
match (a)-[r]->(m) RETURN {id: id(m), name: m.title}}
and something like this (but i don't know how to get relationship source and dest):
match (a)-[r]->(m) RETURN {src: id(r.src), dst: id(r.dst)}
if you could help me it would be awesome ! i hope i'm clear enough.
of course i'm open to any other suggestions or leads!
Thanks in advance!

Knockout mapping does represent wished for html

I have a problem with knockout mapping. I'm using knockout mapping plugin to represent a form that is serialized in JSON. It was working before using the knockout mapping but I need to use knockout mapping since I want my properties to be observable.
You can see the working html here : http://jsfiddle.net/etiennenoel/wG9SZ
Here's my not working javascript code:
var formData =
{"data":
[
{
"groupName" : "Properties",
"content" :
[
{
"title" : "Calculation Method",
"formType" : "select",
"value" :
[
{
"title" : "Voltage Drop - Unbalanced",
"selected" : true
},
{
"title" : "Voltage Drop - Balanced"
}
]
},
{
"title" : "Tolerance (% V)",
"formType" : "textBox",
"value" : 0.01
},
{
"title" : "Calculation Options",
"formType" : "radio",
"value" :
[
{
"title" : "Flat Start (at Nominal Conditions",
"checked" : false
} ,
{
"title" : "Assume Line Transposition",
"checked" : true
}
]
},
{
"title" : "Adjust Conductor Resistance at",
"formType" : "textBox",
"disabled" : true,
"value" : 77,
"appendLabel" : true,
"appendLabelText" : "°F"
}
]
},
{
"groupName" : "Properties",
"content" :
[
{
"title" : "Calculation Method",
"formType" : "select",
"value" :
[
{
"title" : "Voltage Drop - Unbalanced",
"selected" : true
},
{
"title" : "Voltage Drop - Balanced"
}
]
},
{
"title" : "Tolerance (% V)",
"formType" : "textBox",
"value" : 0.01
},
{
"title" : "Calculation Options",
"formType" : "radio",
"value" :
[
{
"title" : "Flat Start (at Nominal Conditions",
"checked" : false
} ,
{
"title" : "Assume Line Transposition",
"checked" : true
}
]
},
{
"title" : "Adjust Conductor Resistance at",
"formType" : "textBox",
"disabled" : true,
"value" : 77,
"appendLabel" : true,
"appendLabelText" : "°F"
}
]
}
]
};
ko.mapping.fromJS(formData);
Here's the jsfiddle of the same code: http://jsfiddle.net/etiennenoel/wG9SZ/3/
What is the problem between when I use mapping and when I don't use it ?
In your second case you forgot to ApplyBindings.
ko.applyBindings(formData);
I don't know if this is the case with your scenario, but it's worth a post.
I had issues with the mapping plugin, when I had a more complex viewmodel with nested properties or lists. It turned out that after mapping to an already constructed viewmodel, the sub-objects were no more observables. With this issue, for me this code worked, what I've found somewhere (unfortunately I already really don't know where). I called this function for my viewmodel after mapping to that.
function makeAllObservables(observable) {
// Loop through its children
for (var child in observable()) {
// If this child is not an observable and is an object
if ((!ko.isObservable(observable()[child])) && (typeof observable()[child] === "object")) {
// Make it an observable
observable()[child] = ko.observable(observable()[child]);
// Make all of its children observables
makeAllObservables(observable()[child]);
}
}
};
Usage (when updating the model from server response, the first line should not be there):
var model = ko.observable({});
ko.mapping.fromJS(myJSObject, {}, model);
makeAllObservables(model);
ko.applyBindings(model);
I ment mapping to an already constructed viewmodel for example, when you want to update your viewmodel with new JSON data from server. In that case I lost nested bindings without the code above.
UPDATE: I've found the source where I borrowed the technique from, here. Note that I slightly modified that code in that post, because somehow that was not working for me.
You need to bind the mapped viewmodel to the view:
ko.applyBindings(ko.mapping.fromJS(formData));
and since everything is now an observable the logic in the view needs to be changed to use the method syntax:
<!-- ko if: $data.formType() === "select" -->
To get the options to display, you need to tell knockout what the property name is on the object:
<select data-bind="options: $data.value, optionsText: 'title'"></select>

Categories

Resources