I am trying to parse a multilevel json file, create a model and then add that model to a backbone collection but i can't seem to figure out how to push the model to the collection. This should be a pretty easy problem to solve, i just can't seem to figure it out. Thanks in advance for your help. Below is my model and collection code:
var Performer = Backbone.Model.extend({
defaults: {
name: null,
top5 : [],
bottom5 : []
},
initialize: function(){
console.log("==> NEW Performer");
// you can add event handlers here...
}
});
var Performers = Backbone.Collection.extend({
url:'../json_samples/performers.json',
model:Performer,
parse : function(data) {
// 'data' contains the raw JSON object
console.log("performer collection - "+data.response.success);
if(data.response.success)
{
_.each(data.result.performers, function(item,key,list){
console.log("running for "+key);
var tmpObject = {};
tmpObject.name = key;
tmpObject.top5 = item.top5;
tmpObject.bottom5 = item.bottom5;
var tmpModel = new Performer(tmpObject);
this.models.push(tmpModel);
});
}
else
{
console.log("Failed to load performers");
}
}
});
As has been said in comments to your question, parse() is not intended to be used this way. If data.results.performers was an Array, all you would have to do is returning it. In your case the code will be slightly different.
var Performers = Backbone.Collection.extend({
...
parse: function(resp, options) {
return _.map(resp.result.performers, function(item, key) {
return _.extend(item, {name: key});
});
}
...
});
On the advice side, if you have the chance to change the API server-side, you'd probably be better off treating collections of objects as arrays and not as objects. Even if it is sometimes convenient to access an object by some ad-hoc key, the data really is an array.
You'll be able to transform it later when you need performers-by-name with a function like underscore's IndexBy
Related
I was going through a stack overflow question on handling collection. The answer given by Brian Genisio was pretty convincing. I have tried his approach as follows:
Collection definition
var PersonCollection = Backbone.Collection.extend({
model : Person,
url: '/people',
parse: function(resp, xhr) {
this.header = resp.header;
this.stats = resp.stats;
return resp.people;
}
});
Collection usage
var personCollection = new PersonCollection();
personCollection.fetch();
console.log(personCollection.header); //undefined
console.log(personCollection.status); //undefined
The collection is fetching models perfectly but I am getting other assigned properties as undefined. Please suggest me a solution to fix this issue.
You need to wait till the fetch is done.
personCollection.fetch().done(() => {
console.log(personCollection.header);
console.log(personCollection.status);
});
In the code below, the fetch() and sync() methods are not doing anything.
I am trying to see how the data in my localStorage gets updated and the methods are not updating it (example LS string is in the code)
Where am I going wrong?
function makeWorkingLS(collDesc, projDesc, Id, Description, ElapsedSeconds, ElapsedTime, WorkItemType){
//Create observable object from params
var activeTaskObject = kendo.observable ({
client: collDesc,
project: projDesc,
taskId: Id,
description: Description,
elapsedSeconds: ElapsedSeconds,
elapsedTime: ElapsedTime,
comment: WorkItemType
});
// example string in localStorage:
//{"client":"Morken Mindy","project":"Shazbat creation engine","taskId":183,"description":"Create the Shazbat 100% efficiency engine","elapsedSeconds":296803,"elapsedTime":"82h43m","comment":"Task"}
// Convert to JSON string for localStorage
var activeTask = JSON.stringify(activeTaskObject);
console.info(activeTask);
//Write to localStorage
window.localStorage.setItem("activeTask",activeTask);
//Set it as the active datasource for updating to webservice
var activeTaskDS = new kendo.data.DataSource({
transport: {
read: function(options){
taskItem = JSON.parse(localStorage["activeTask"]);
},
update: {
url: remUpd, //url var declared earlier in the process
dataType: "json"
}
},
schema: {
model: {
client: "client",
taskId: "taskId"
},
data: function(){
return taskItem;
}
}
});
activeTaskDS.fetch(function(){
activeTaskDS.data()[0].set("client", "NOBODY");
activeTaskDS.sync();
cosole.log("activeTaskDS.data()[0] : "+activeTaskDS.data()[0]); //should read 'NOBODY' but reads 'Morken Mindy'
});
}
Thanks in advance,
Neil.
I'm not sure what is the problem actually, but I have to point some important things:
AFAIK, when you customize any transport methods you have to pass the data into a callback in the options object:
transport: {
read: function(options){
taskItem = JSON.parse(localStorage["activeTask"]);
// Tells the widget to handle that collection
options.success(taskItem);
}
}
In schema.data it seems that you want to pass your data through this method(correct me if I'm wrong). But this method isn't for that purpose. It is used just to tell the widget which field to read(in case of passing a string to it) or to read a property from a response, which comes as a parameter that you are not using. Check the second example here. So this may not be right way to read the taskItem object as data;
Speaking about the taskItem object, it seems that its the base data of your dataSource but it isn't defined(at least on the snippet you posted). What I mean is, if you follow the step 1 you won't even need to read from that object no more.
Please let me know if this is helpful and if you need anyting more.
I have an object in Ember (let's call it existing):
var existing = {
items: [
...
],
...
}
On the callback of hitting a server side request, there is a new response called result which looks the same as existing. I need to take the items in existing, and prepend them to the new result. So I have the following:
var result = { ... };
var existing = this.get('content');
result.items = result.items.concat(existing.items);
this.set('content', result);
The problem is, when rendered in the template, it is just displaying the new items from result, the old items from existing are not being displayed even though are in items. Any ideas why?
Thanks.
I guess the problem is that using concat which is not supported in Ember.Array (http://emberjs.com/api/classes/Ember.Array.html) does not trigger bindings and therefore your view is not updated. To get the items arrays merged you could do something like:
var result = { ... };
var existing = this.get('content');
result.items.forEach(item) {
existing.items.pushObject(item);
}
this.set('content', existing);
Hope it helps
If result.items is an array and you want to use the javascript concat method you can call toArray on the existing.items enumerable.
var result = { ... };
var existing = this.get('content');
result.items = result.items.concat(existing.get('items').toArray());
this.set('content', result);
If result.items is already an Ember.Enumerable I would use pushObjects or addObjects. http://emberjs.com/api/classes/Ember.MutableArray.html#method_addObjects
var result = { ... };
var existing = this.get('content.items');
result.items = result.get('items').addObjects(existing);
this.set('content', result);
I see this is an old post, but since there isn't an accepted answer, I thought I'd throw in what I feel is the best option. I recently found myself needing to concat a bunch of DS.ManyArray together and this was the solution I came up w/:
var myArrayOfHasManyArrays = ...;
var concatenated = [].concat.apply([], myArrayOfHasManyArrays.invoke('toArray'));
Hope this helps!
I just recently started using Backbone.js and I'm working on an app now using Brunch that does a JSONP request to an external API to populate my collection and models. I'm following these previous posts (this and this) on doing JSONP requests with Backbone, but my collection still isn't getting the data for some reason.
My model (app/models/model.js):
module.exports = Backbone.Model.extend({
});
My collection (app/models/collection.js):
var Post = require('./model');
module.exports = Backbone.Collection.extend({
model: Post,
url: "http://somedata.com/api/posts/list/stuff",
sync: function(method, model, options) {
options.timeout = 10000;
options.dataType = "jsonp";
options.jsonp = "JSONPcallback";
return Backbone.sync(method, model, options);
},
parse: function(response) {
if (response) {
var parsed = [];
for(var i = 0; i < response.results.length; i++) {
parsed.push(response.results[i][0]);
}
return parsed;
}
}
});
Then, in the initialize method in app/application.js I'm calling it by:
var Category = require('models/collection');
this.cat = new Category();
this.cat.fetch();
Now, when I look at the parse function in console.log, I see the data being fetched, so the request is going through successfully. However, when my views are rendered and I do console.log(application.cat.models) in app/views/view.js, I get nothing -- why's this happening? Is there anything wrong with the code on my model/collection?
Also, the JSONP data has the following format, which is why looping through for response.results[i][0] and returning an array with all of it, that should do the trick, right?
{"results":[
{"0":{"id":xxx,"title":xxx,"link":xxx},
"description":xxx},
{"0":{"id":xxx,"title":xxx,"link":xxx},
"description":xxx},
{"0":{"id":xxx,"title":xxx,"link":xxx},
"description":xxx},...
]}
Would really appreciate any help...
I have 2 comments here :
I see that you have names both your model and collection as module.exports , a common practice is to make the model as singular (module.export) and make the collection for those models plural module.exports , just common practice , nothing "wrong" otherwise
You can have 2 callbacks in your code , when the collection is done fetching data(asynchronous event) also considering module.exports as your collection here ,
A. You could do this :
module.exports.fetch({
success : function(data){
console.log(JSON.stringiy(data));
//do remaining programming here
}
});
B. you could have a event listener for reset , from the documentation here , the collection fires a reset event when it completes the fetch , so could add an event listener on the collection like this :
module.exports.on('reset',function(data){
console.log(JSON.stringify(data));
//do remaining programming here
},this);
I am creating a client view of an application and I need help with retrieving specific data from my JSON file. I am using Backbone.js along with Underscore.js to achieve this.
(function($) {
window.Node = Backbone.Model.extend({
getName: function(){
return this.get('Name');
}
});
window.Nodes = Backbone.Collection.extend({
model:Node,
url: '/packageview.json'
});
window.NodeView = Backbone.View.extend({
tagName: "div",
className: "package-template",
events:{
"click #display-name" : "displayname",
},
//.. I have a render and initialize function here which should not be a concern
displayname: function(){
var node = new Node();
alert(node.getName()); //trying to alert
},
});
});
I am trying to get the name from model and alert it. I have a button in my html with an id, and when I press that button I get "undefined" as an alert. Here is how my JSON file looks:
{
"Id": 2,
"Name": "Some Package",
"IsComplete": false,
"IsNodeTagComplete": false
}
I think I am making a silly mistake somewhere. Am I expecting way to much from model?
What I am doing here is this
window.jsonAccess = Node.extend({ // Here Node is my above mentioned model
getJSON: function(){
var collection = nodeInstance.toJSON(); // nodeInstance is an instance of my collection Nodes
return collection; //returns JSON
}
});
jAccess = new jsonAccess();
So here is what I am doing to access the JSON
getNodeId: function(){ //Function to get Node Id from JSON
objectJSON = jAccess.getJSON(); // Get JSON
_.each(objectJSON, function(action){
_.each(action.Nodes, function(action){
This solves my purpose but not quite the way getters would be used in backbone.
Since a lot of context is missing I too may be making a mistake but here's my guess - you are creating an empty Node Model. Try doing something like this in display:
displayName: function() {
var myJSON = window.getJSONObject(); //wherever your json object is or how to get it...
var node = new Node({
id:myJSON.Id,
name:myJSON.Name,
isComplete: myJSON.IsComplete,
...
});
alert(node.get('name'));
alert("Getter: "+node.getName()); //your version...
}
This is just a hunch though...maybe I'm missing your context but this seems to be the case for now...