How to build a Collection/Model from nested JSON with Backbone.js - javascript

I'm relativly new to Backbone.js
I have a JSON like the picture shows !
I saw some Answers in relation with Backbone-relational, but still dont get the point!
How can i convert this JSON to Backbone.js Collections/Models??
I update with a code but it dont work like expected! i can't see an model when i do :
My Structure is :
[0] : is a collection of models
[clefs] + ... + [Rest] : are collection of models
(clefs) => [0] + ... + [9] : are Models(title contains a string, path too)
Thanks a lot!!
EDIT(10.01.12) :
My Solution :
window.initModel = Backbone.Model.extend({
defaults: {
"title": "",
"path": ""
}
});
window.CustomCollection = Backbone.Collection.extend({
model: initModel
});
window.Init = Backbone.Model.extend({
url : function(){
return "/api/data.json"
},
parse: function(response) {
clefs = new CustomCollection();
clefs.add(response.clefs);
this.set({clefs: clefs});
.....
rests = new CustomCollection();
rests.add(response.rests);
this.set({rests: rests});
}
});
this helped me out too!

I'm at work, so I cannot give you a fully coded answer, but the gist is, you can do the following in your top level models to achieve a nested model hierarchy:
var AmericasNextTopModel = Backbone.Models.extend({
initialize: function(){
this.set({
clefs: new ClefCollection(this.get('clefs')),
accidentals: new AccidentalCollection(this.get('accidentals')),
notes: new NoteCollection(this.get('notes')),
rests: new RestCollection(this.get('rests'))
});
}
});
I do not use backbone-relational so I cannot give you an answer regarding that.
Are you making an online sheet music viewer/editor? :D Cool I'd love to see it when you're done.

The reset method (see 'reset') allows you to pass a JSON array to a collection.
This is the equivalent of a PUT method, replacing the specified collection with the JSON hash.
You can also use the add method to add to an existing collection, or pass the JSON hash into the constructor as you create a new collection.
You'll have to do some basic cleaning up of your array to get it in an appropriate format, and then convert it to JSON

I'm using PHP to grab a feed as JSON since it's on a different domain. I save those results to a JS variable, and then I just had success using this to get it into my Backbone collection...
var feedCollection = new Backbone.Collection();
feedCollection.set(myFeedJSON.nestedObject.nestedArrayIWant);

Related

knockoutjs - ko.mapping.fromJS not working

I have just started trying knockout.js. The ko.mapping offers a nifty way to get and map data from server. However I am unable to get the mapping to work.
I have a simple model:
//var helloWorldModel;
var helloWorldModel = {
name: ko.observable('Default Name'),
message: ko.observable('Hello World Default')
};
$(document).ready(function() {
ko.applyBindings(helloWorldModel);
//a button on the form when clicked calls a server class
//to get json output
$('#CallServerButton').click(getDataFromServer);
});
function getDataFromServer() {
$.getJSON("HelloSpring/SayJsonHello/chicken.json", function(data) {
mapServerData(data);
});
}
function mapServerData(serverData) {
helloWorldModel = ko.mapping.fromJS(serverData, helloWorldModel);
alert(JSON.stringify(serverData));
}
The helloWorldModel has only 2 attributes - exactly the same thing I return from the server. The alert in mapServerData shows -
{"name":"chicken","message":"JSON hello world"}
I have looked up other posts regarding similar problem, but none of them seemed to be solve this issue. Maybe I am missing something very basic - wondering if anyone can point it out.
Also note if I do not declare the model upfront and use
helloWorldModel = ko.mapping.fromJS(serverData);
it is mapping the data to my form correctly.
From Richard's reply and then a little more investigation into this I think that the way I was initializing the model is incorrect. I guess that one cannot use an existing view model and then expect it to work with mapper plugin. So instead you initialize view model with raw JSON data using the ko.mapping.fromJS:
var helloWorldModel;
$(document).ready(function() {
var defaultData = {
name: 'Default Name',
message: 'Hello World Default'
};
helloWorldModel = ko.mapping.fromJS(defaultData);
ko.applyBindings(helloWorldModel);
$('#CallServerButton').click(getDataFromServer);
});
function getDataFromServer() {
$.getJSON("HelloSpring/SayJsonHello/chicken.json", function(data) {
mapServerData(data);
});
}
function mapServerData(serverData) {
alert(JSON.stringify(serverData));
ko.mapping.fromJS(serverData, helloWorldModel);
}
This code works and provides the expected behavior
You can't just overwrite your model by reassigning it this way.
When you do:
ko.applyBindings(helloWorldModel);
You are saying "bind the model helloWorldModel to the page". Knockout then goes through and hooks up the observables in that model and binds them with the page.
Now when you overwrite your form model here:
helloWorldModel = ko.mapping.fromJS(serverData, helloWorldModel);
It is overwriting your model object with a brand new object with entirely new observables in it.
To fix it you need to change this line to just:
ko.mapping.fromJS(serverData, helloWorldModel);
This takes care of the properties inside the model and reassigns them for you, without overwriting your model.

how to use jQuery so that value updates when new JSON is loaded

Within my Ember Model when I load data the first time it works. But, when I perform a second load the value in my each statement contains the values from the first load. How can I fix this? I have a feeling there is a simple (and possibly even elegant) solution to this.
Here is my model:
Hex.Asset = Ember.Object.extend({
id: null,
assets:[]
});
and the problem is here:
return Ember.$.getJSON("/arc/v1/api/posts/" + id).then(function(d){
var data= d.post;
var post = Hex.Post.create();
post.set('id', data.id);
// HERE'S THE PROBLEM
$.each(data.assets, function(index, value){
var asset = Hex.Asset.create();
asset.set('id',value.id);
console.log("here is id:" + value.id);
});
First json:
{
"post":{"id":1, assets:[{"id":23}]}
}
Second json:
{
"post":{"id":1, assets:[{"id":25}]}
}
After second load outputting id of 23 for asset and should be 25.
EDIT #1
After thinking about this, I can do the following:
post.assets=[]; // part added
$.each(data.assets, function(index, value){
var asset = Hex.Asset.create();
asset.set('id',value.id);
});
But is there a way not to set this this way?
You should define the assets property in Post to a relationship:
Hex.Post = DS.Model.extend({
assets: DS.hasMany('asset', {async: true})
});
Then you can do this:
var post= Hex.Post.create(d);
No need to explicitly name an id property, it is automatic.
EDIT:
Since you mention Model, I'm assuming you're using Ember Data, even though your code snippet shows you extending Ember.Object. Are you using Ember Data Model? If so, you should extend DS.Model as I have shown.

In jsTree , How to get Node information by node id?

In jsTree ,How to get Node information by node id ?
I know id of following node i.e 295 then how to get complete node information
<item id="295" parent_id="192" title="itemTitle" version="1">
<content><name>Bhushan Sambhus</name></content>
</item>
above xml part rendered into jsTree is as follows
$("#treeViewDiv").jstree({
"xml_data" : {
"data" : "" +
"<root>" +
"<item id="295" parent_id="192" title="itemTitle" version="1">"+
"<content><name>Bhushan Sambhus</name></content> "+
"</item>"
}
"plugins" : [ "themes", "xml_data","ui" ]
});
Something like following psudo code
function getNodeByNodeID(node_id){
// some code
// $.jstree.get_node ...... etc ?
//
return relatedNodeInformation;
}
var nodeInfo = getNodeByNodeID(providedNodeID) // psudo code
// any api in jstree to get nodeInfo by providedNodeID?
var parent_id_value = nodInfo.attr("parent_id");
var title_value = nodInfo.attr("title");
var version_value = nodInfo.attr("version");
var node_name = nodInfo.children("a").text()
alert(parent_id_value+" :: "+title_value+" :: "+version_value+" :: "+node_name);
Input : 295
Output: 192 :: node_name :: 1 :: node_name
Any help or guidance in this matter would be appreciated
If I'm understanding your question correctly, you can accomplish what you want to do like this:
var nodInfo = $("#" + providedNodeId);
var parent_id_value = nodInfo.attr("parent_id");
var title_value = nodInfo.attr("title");
var version_value = nodInfo.attr("version");
var node_name = nodInfo.children("a").text();
alert(parent_id_value+" :: "+title_value+" :: "+version_value+" :: "+node_name);
Just want to help keep the answer up-to-date. Using jstree 3.1.0, node objects (not DOM objects) are fetched by using this code:
var treeMain; // reference holder
$(document).ready( function () { // when the DOM is ready
treeMain = $('#treeMenus').jstree(); // create the tree and get the reference
});
function getNode( sNodeID)
{
return $.jstree.reference(treeMain).get_node(sNodeID); // use the tree reference to fetch a node
}
I've seen several answers to this question on StackOverflow that all talk about getting back to the DOM object of a tree item. I'm willing to bet that most people asking this question really want to get back to the underlying JSON data object of a tree item, which is why they say they want the node object (which has the .original property). Specifically, you need this for implementing things like "create" functionality where you need to create a new JSON data object with a ParentID that is set to the ID of the parent JSON data object. I searched for 2 days and didn't find anything clear in the jstree documentation that explained this:
$.jstree.reference(treeMain).get_node(sNodeID);
simple call. In their defense, they do have a 1 line example buried in here:
http://www.jstree.com/docs/interaction/
but it's an example most people won't care about (the user will be selecting nodes most of the time), and certainly not clear for what it is actually capable of doing. Anyways... hope this is helps save someone else a couple of days. =)

Backbone.js relations

I'm having an issue wrapping my head around relational models in Backbone. I've just started using it and I'm tasked with a fairly large application.
The main issue I'm having is that I have a model that should contain a collection.
This is what I have to work with:
modelA
id: _id
url: api/model/:modelA_id
nested:
url: api/:modelA_id/nest
I think I'm making it a bigger deal than I need to, but I just can't seem to wrap my head around how to set this up.
Any help will be most appreciated.
The biggest thing to wrap your head around with Backbone is how to properly use events to deal with basically everything in the app. The other big thing to understand is that there are probably 5 different ways to attack a problem, where none of them are better/worse than the other.
Given that loose structure you've provided, I would do something like:
var YourApp = {
Models : {}
Collections : {}
Views : {}
};
YourApp.Models.First = Backbone.Model.extend({
initialize : function(){
var nestedCollection;
this.url = 'api/model/' + this.id;
nestedCollection = new Backbone.Collection({
url : this.url + '/nest'
});
this.set('nested', nestedCollection);
}
});
new YourApp.Models.First({
id : 23
});

How do I reference the local variable when creating Url.Action call?

Backstory: To specify the correct route for a jqGrid that I show on my ASP.NET MVC 3 page, I do something like so:
$('#jqgFlavors').jqGrid({
url: '#Url.Action("FlavorData", "IceCream")',
etc...
and that will produce the correct route either when running locally out of Visual Studio (where things live at something like "http://localhost:90125/IceCream" or on the deployed site where things live at something like "http://thehostsite/mydeployedsitename/IceCream".
Great. Now the issue I'm having is that I use the onSelectRow in the grid to do a master/details thing based on the selected row's flavor id value. First, I tried doing this to just get the route correct:
onSelectRow: function(theRow){
$('#flavorDetails').load('#Url.Action("Details","IceCream", new {id = 42)})');
}
So that I can pass the value 42 in as the 'id' parameter in the Details action of the IceCream controller. And that works fine, but of course I don't want to hard code the value 42, rather pull the flavor id from the grid itself. So I have tried to reference the flavorID but can't seem to get the syntax correct:
onSelectRow: function(theRow){
var grid = jQuery('#jqgFlavors');
var flavorID = grid.jqGrid('getCell', theRow, 'FlavorID');
$('#flavorDetails').load('#Url.Action("Details","IceCream", new {id = flavorID)})');
}
I'm sure you get what I'm going for here - referencing the flavorID value I extract from the grid. But what I get is a compilation error:
The name 'flavorID' does not exist in the current context.
I suspect this is really simple. How do I reference correctly that variable?
You could use the second argument of the .load() method which allows you to pass additional parameters:
var flavorID = grid.jqGrid('getCell', theRow, 'FlavorID');
$('#flavorDetails').load('#Url.Action("Details", "IceCream")', { id: flavorID });
This might probably use the following url: /IceCream/Details?id=123 instead of what you might want /IceCream/Details/123 because javascript doesn't know anything about your routes but why care? It will still map correctly to the controller action:
public ActionResult Details(int id)
{
...
}
But if you are really anal about urls and insist on having the first type of url I've seen people doing the following:
var flavorID = grid.jqGrid('getCell', theRow, 'FlavorID');
var url = '#Url.Action("Details", "IceCream", new { id = "_TOREPLACE_" })';
url = url.replace('_TOREPLACE_', flavorID);
$('#flavorDetails').load(url);
Personally I wouldn't do it but providing it just for the record.

Categories