Why is my dijit.Tree not populated from json source? - json

I am new to dojo and spring development. I am trying to populate a Tree widget using a json response from a spring-mvc controller. I'm following the examples from the dojocampus website quite closely.
Firstly if I use a local data source it works ok:
<script type="text/javascript">
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.Tree");
dojo.addOnLoad(function() {
var rawdata = [{"rid":"b1c","name":"Test Parent","children":[{"rid":"1c4","name":"Test Child 1","children":[]},{"rid":"ee6","name":"Test Child 2","children":[]}]}];
var store = new dojo.data.ItemFileReadStore({
data: {
identifier: 'rid',
label: 'name',
items: rawdata
}
});
var treeModel = new dijit.tree.TreeStoreModel({
store: store,
query: {name: 'Test Parent'},
childrenAttrs: ["children"]
});
new dijit.Tree({
model: treeModel
},
"treeOne");
});
</script>
<div id="treeOne">
</div>
But if I use my json url the tree doesn't appear:
<script type="text/javascript">
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.Tree");
dojo.addOnLoad(function() {
var store = new dojo.data.ItemFileReadStore({
url: "/Demo2/glossaryobjects/categories.json"
});
var treeModel = new dijit.tree.TreeStoreModel({
store: store,
query: {name: 'Test Parent'},
childrenAttrs: ["children"]
});
new dijit.Tree({
model: treeModel
},
"treeOne");
});
</script>
<div id="treeOne">
</div>
When I debug with Firebug I can see that the json response appears to be loaded correctly. It looks like this:
{"identifier":"rid","items":{"rid":"b1c","name":"Test Parent",
"children":[{"rid":"1c4","name":"Test Child 1","children":[]},
{"rid":"ee6","name":"Test Child 2","children":[]}]}, "label":"name"}
There is an error in Firebug:
"dijit.tree.TreeStoreModel: query {"name":"Test Parent"} returned 0 items, but must return exactly one item"
It looks like the ItemFileReadStore is not correctly loaded. Anyone know what I'm doing wrong? I've been tearing my hair out for days trying to get this to work, so any help is much appreciated.
Cheers,
Rod.

OK! Problem solved (for me):
If you have a close look at the store produced by each, the data is there for both, but the way the store represents each is different.
With the url JSON data, you get
_arrayofallitems []
_arrayoftoplevelitems Object {....
id...
items...
etc.
with the string data, you get
_arrayofallitems [] 62 items
_arrayoftoplevelitems
[0]
id
items
etc.
If you intercept the JSON response from xhrGet, and compare it to the string, you'll see that the JSON response is not an array (no []) whereas the string is.
Solution: declare an empty array, push the JSON response into it,
then pass the array to ItemFileReadStore:
dojo.xhrGet( {
url: 'test.php',
handleAs: "json",
preventCache: 'true',
load: function(response, ioArgs){
var rawdata = [];
rawdata.push(response);
var store = new dojo.data.ItemFileReadStore({ data: {
identifier: "id",
label: "label",
items: rawdata }
});
loadtree(store);
}});
It worked for me (finished an afternoon of frustration)...

The error you mentioned:
"dijit.tree.TreeStoreModel: query {"name":"Test Parent"} returned 0 items, but must return exactly one item"
Should be from using a TreeStoreModel instead of a ForestStoreModel. The former requires only one item be returned for the root node. Your fix probably worked because you shoved it into a single array.
Take a look at:
http://ofps.oreilly.com/titles/9780596516482/application_widgets.html

Related

calling a dojo JsonRest with parameters

When calling JsonRest using dojo, how can I pass parameters with it.
var rest = new JsonRest({
target: "/path/to/service"
});
JsonRest example:
require(["dojo/store/JsonRest"], function(JsonRest){
// create a store with target your service
var store = new JsonRest({
target: "/path/to/service"
});
// make a get request passing some options
store.query("foo=bar", {
start: 5,
count: 5,
sort: [
{ attribute: "color", descending: true }
]
}).then(function(results){
// result here
});
});
The function to use in your case is query with signature query(query, options)
When called, query will trigger a GET request to {target}?{query}, as described in dojo docs.
Please keep in mind that:
If query is an object, it will be serialized.
If query is a string, it is appended to the URL as-is.
If options includes a sort property, it will be serialized as a query parameter as well;
Your service/API should:
Return a array of objects in JSON format.
Return an empty array if no match is found.

Backbone model .toJSON() doesn't work after .fetch()

Good day! I need to render a model's attributes to JSON so I can pass them into a template.
Model:
var UserInfo = Backbone.Model.extend({
url: appConfig.baseURL + "users/",
});
Template:
<script type="text/html" class="template" id="profile-form">
<h2 class="ui-li-heading"><%= username %></h2>
<p class="ui-li-desc"><strong><%= phone %></strong></p>
</script>
View:
var ProfilePageView = Backbone.View.extend({
events: {
'click #edit': "edit"
},
initialize: function () {
this.template = $.tpl['profile-form'];
var user = new UserInfo()
user.fetch({
data: $.param({email: localStorage.getItem('user_email')}),
type: 'POST'
});
console.log(user) //returns correct object with attrs
console.log(user.toJSON()) //returns empty object
},
render: function (eventName) {
$(this.el).html(this.template());
},
edit: function () {
window.workspace.navigate('#account/edit', { trigger: true});
}
});
When i put in console something like this, user.toJSON() returns correct data
var user = new UserInfo();
user.fetch({
data: $.param({email: localStorage.getItem('user_email')}),
type: 'POST'
});
But when i put it to my view, its returns Object {}.
Where is a mistake or tell me how can differently pass to the template data received from the server in json format? Thanks!
You appear to have two problems. fetch is asyncronous, so you need to use a callback to use the information. But first, an explanation about toJSON. .toJSON() doesn't actually return a JSON string, it returns an object that is what you want JSON to stringify. This allows you to modify the toJSON method to customize what attributes will be taken from your model or collection and added to the JSON string representation of your model. Here is a quotation from the Backbone.js docs:
toJSON collection.toJSON([options])
Return a shallow copy of the model's attributes for JSON
stringification. This can be used for persistence, serialization, or
for augmentation before being sent to the server. The name of this
method is a bit confusing, as it doesn't actually return a JSON string
— but I'm afraid that it's the way that the JavaScript API for
JSON.stringify works.
So you should replace this line in your code
console.log(user.toJSON())
with this one
console.log(JSON.stringify(user))
The object that you saw was returned by toJSON will then be turned into JSON.
Now, even after you do that, it won't work properly, because you will execute the console.log before you get the data for your model from fetch. fetch is asynchronous, so you need to call any code you want to be executed after the fetch is done in the success callback:
user.fetch({
data: $.param({email: localStorage.getItem('user_email')}),
type: 'POST',
success: function(){
console.log(user);
console.log(JSON.stringify(user));
}
});

Populate Dojo's datagrid with JsonRest and custom json arrays

I have a grid that I am creating drawing off a JSON data source that is formatted like this:
[{"user":{"username":"foo","url":"bar"}},
[{"product":{"name":"banana","price":"85"}},
{"product":{"name":"peach","price":"66"}},
{"product":{"name":"strawberry","price":"78"}}
]
]
But I cannot figure out how to tell datagrid to use the contents of the products to populate the datagrid. Here is my datagrid code:
<script>
require(["dojo/store/JsonRest"], function (JsonRest) {
myStore = new JsonRest({ target: 'myurl', handleAs: 'json'
});
});
require(["dojox/grid/DataGrid", "dojo/data/ObjectStore", "dojo/domReady!"
], function (DataGrid, ObjectStore) {
grid = new DataGrid({
store: dataStore = new ObjectStore({ objectStore: myStore }),
structure: [
{ name: "Procuct", field: "name", width: "200px" }
]
}, "grid3");
grid.startup();
});
</script>
<div id="grid3"></div>
I do not get any error, but I cannot see that the grid gets populated.
It is a similar question to THIS, but the data structure is a bit different.
I think it has something to do with your json structure.
The first part of your jsonArray is an object, the second an array:
[object,ArrayOfProducts]
How should DataGrid find the necessary data if you hide it in an array within an array & then inside the attribute product.
Try passing something simple via json like:
[{"name":"banana","price":"85"},
{"name":"peach","price":"66"},
{"name":"strawberry","price":"78"}]
Have you tried grid.renderArray(dataStore) to populate the grid with the conent ?
An option is to append a new property to the json object prior to dataStore.query() call. This can be accomplished with dojo/aspect. See article for other examples.
aspect.before(dataStore, "query", function(items) {
items.forEach(function(item) {
//Do something here. I'll combine two properties.
item.newProperty = item.propertyValueA + "-" item.propertyValueB;
return item;
});
return items;
});
When dataStore.query() is called, the function above is called above. This results in a new property be added to the json object. In the example above, the newProperty is a concatenation of propertyValueA and propertyValueB.
This may allow you to manipulate the json as needed.

parse urls in Backbone.js

I am new to Backbones.js, and I was trying to get my JSON urls and parse them correctly.
This is my code:
window.Post = Backbone.Model.extend({
initialize: function(options) {
this.id = options.id;
},
url: function() {
return 'api/get_post/?post_type=movies&id=' + this.id;
},
parse : function(response) {
return response.posts;
},
});
window.Posts = Backbone.Collection.extend({
model: Post,
defaults: {
model: Post,
},
url: "api/get_recent_posts/?post_type=movies",
parse : function(response) {
return response.posts;
},
});
It seems that parsing for both overrides each other or something. when I remove the parse option from the Post class, I get a full response from the collection, but not from the model.
Are there any clear examples on how to set parsing for different son hierarchies? my JSON result have a status ok before it dives into the actual data.
I've never used bones.js but maybe these examples will help.
I think what you want to do is get rid of the parse() function in your collection. This assumes that since it is a Post collection, your data will come in as an array of Post JSON objects [{id:'1', 'sub':{data}},{id:'2', 'sub':{data}},{id:'3', 'sub':{data}}] or something like that.
If your Post model has sub-models or collections, your model parse() will then take the sub-object property name and do something with it.
// In Post Model definition
parse:function(response) {
if (response.sub) {
// create some model or collection etc.
}
}
You might have to pass an option parse:true when you do your collection fetch.
I posted something along these lines which might help you see how sub-models can be instantiated on fetch calls.
Backbone.js: Load multiple collections with one request
Cast/initialize submodels of a Backbone Model
I hope this helps.

Load data from bd in senchaTouch app using webservice who return a json

I try to display some data in my Sencha touch application, but it doesn't work... and i can't find what I'm doing wrong.
My webSiste return a json object who look like this
[{"name":"a","id":1}]
the script is getting the Json and display it:
Ext.regApplication({ name: 'Command',
phoneStartupScreen: 'phone-startup.png',
phoneIcon: 'apple-touch-icon.png',
launch: function(){
this.viewport = new Ext.Panel(
{
layout: 'fit',
fullscreen: true,
items: [{xtype: 'list',
itemTpl: new Ext.XTemplate('<div>{name}</div>'),
store: stores
}],
dockedItems: [{xtype: "toolbar",
dock: "top",
title: 'MovieCommand',
items: [{ui: 'back',text: 'back',handler: function(){}}]
}]
});
}
});
Ext.regModel('Commands', {
fields: ['name', 'id' ]
});
var stores = new Ext.data.Store(
{model: 'Commands',
proxy: {type: 'scripttag',
url: 'http://localhost:8080/GTI710/commandes/liste.htm',
format: 'sencha',
reader: new Ext.data.JsonReader ({
type: 'json',
})
},
});
stores.load();
I don't have any error in the java script but nothing is displayed.
I just want to have the "a" displayed but it doesn't work, I don't know why...
The ScriptTagProxy, which you are using, requires a response from server that's composed of legitimate Javascript code.
Specifically, the code is a callback function with the desired JSON data you what as the its first argument:
someCallback([{"name":"a","id":1}]);
The name of someCallback is generated dynamically by Sencha Touch when the request is sent. In other words, your attempt to store the response with a static file will not work.
The name of someCallback is passed as a parameter in the GET request sent by Sencha Touch, the key of which defaults to callback.
If you don't want to have a web server as the data source, checkout Ext.util.JSONP.