Backbone.js collection fetch not setting response objects as models - backbone.js

When fetching a collection, my api response has 10 objects, but the resulting Backbone collection only has 1 model with an attributes array containing the 10 response objects....to put it another way, the fetch is not creating models out of the objects in my response...and I don't know why.
Model definition:
MyApp.Item = Backbone.Model.extend({
initialize: function(){
}
});
Collection definition:
MyApp.ItemCollection = Backbone.Collection.extend({
model: MyApp.Item,
url: '/api/v1/item/',
parse : function(response){
//api returns objects in the content attribute of response, need to override parse
return response.content;
}
});
Calling fetch:
var myCollection = new MyApp.ItemCollection();
myCollection.fetch({
traditional: true,
data: { //url params for api call
u_id: currentUser.id,
order: 'sort_date:desc',
start: 0,
num_items: 10,
format:'json'}
});
Results:
console.log(response.content);
4571221007823F95BAAFB2BDF81111XX: Object
0124207763051005AAF59694458EBFXX: Object
3324207755431003B589CEF237DBE1XX: Object
3470000061641005BFB5D9983156E0XX: Object
3515553061641005A02884677F5624XX: Object
3526033426761006AFEA9852B0DDB5XX: Object
21431252714010079E4D8413429DB0XX: Object
26570547220410068F60D1B07D2E08XX: Object
37557124663710079DDC81EE855981XX: Object
0152243312031007957B94F5073B69XX: Object
//api successfully returns an array of objects, with GUID as key
console.log(myCollection);
r {length: 1, models: Array[1], _byId: Object}
//why only one model? why not 10?
console.log(myCollection.models[0].attributes);
4571221007823F95BAAFB2BDF81111XX: Object
0124207763051005AAF59694458EBFXX: Object
3324207755431003B589CEF237DBE1XX: Object
3470000061641005BFB5D9983156E0XX: Object
3515553061641005A02884677F5624XX: Object
3526033426761006AFEA9852B0DDB5XX: Object
21431252714010079E4D8413429DB0XX: Object
26570547220410068F60D1B07D2E08XX: Object
37557124663710079DDC81EE855981XX: Object
0152243312031007957B94F5073B69XX: Object
__proto__: Object
//there they are...but why?
How can I change the fetch to get these objects added as individual models in myCollection?

The response must be an array. Each item in the array is turned into a model. Your response is an object.
Update your parse method to pull out the values (as an array) from the response into an array and it'll work.
MyApp.ItemCollection = Backbone.Collection.extend({
model: MyApp.Item,
url: '/api/v1/item/',
parse : function(response){
//api returns objects in the content attribute of response, need to override parse
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
});

Related

Get one Post back in backbone via fetch on a collection

I have the following collection:
AisisWriter.Collections.Posts = Backbone.Collection.extend({
model: AisisWriter.Models.Post,
// Build the url based on blog id.
url: function() {
url = '/api/v1/blogs/' + AisisWriter.blog_id + '/posts/'
return url;
}
});
this allows me to do:
var options = { reset: true };
this.writer_posts.fetch(options).then(this.postsRecieved, this.serverError);
this will return me all posts, current six.
I have tired to do:
var options = { reset: true };
this.writer_posts.fetch({id: id}).then(this.postsRecieved, this.serverError);
// id is the id passed into the route, in this case it's #=> {id: 6}
But this still returns me all six posts, I have seen this answer, but I don't think I should have to go through, or extend the model in the middle of code just to append an ID, that and I use the model for the Post, Put and Delete actions while I use the collection for fetching data.
So how do I return one post?
In general, to get some Model from Collection, you should fetch Collection and then get needed model by id, for example:
this.writer_posts.fetch();
And after Collection will be fetched you get method
this.writer_posts.get(id);
Or you can try to fetch a specific Model by passing required id in the fetch method:
this.writer_posts.fetch({
data: {
id: id
}
});
Or something like that.

convert super model into inner model

I have backbone models hierarchy like
ModelA = Backbone.Model.extend({
initialize : function(){
this.set("prop1",10);
}
});
ModelB = ModelA.extend({
this.set("prop2",new ModelC())
});
ModelD = ModelA.extend({
this.set("prop3",new ModelE())
});
ModelC and ModelE are also Backbone models.
I wanted to store ModelB and ModelD objects into 1 collection So
I created collection like
collection = Backbone.Collection({
model : ModelA
});
Here what I'm doing -
I store ModelA objects into collection
Converting collection into json.
Recreating collection from json.
Here I'm getting ModelA objects from collection but want objects of specific type like ModelB, ModelD etc.
How can I achieve this?
You can trick it into creating the correct Model as #McGarnagle said by providing an attribute that specifies the type then specify a custom constructor for your collection,
collection = Backbone.Collection({
model : function(attrs, options){
if(!attrs || !attrs.modelType)
return new ModelA(attrs, options)
if(attrs.modelType === 'ModelB')
return new ModelB(attrs, options)
//etc...
}
});

Backbone, get a Collection by collection ID (not RESTful)

I have a backbone collection where the collection is fetched by a url with an id parameter (not RESTful)
url: '/api/categories/?level=2&id=',
So id might be
&id=2
or
&id=45
How do I go about doing this? I've been reading different posts and some say to override Backbone Sync and others say to just do a fetch but modify the data parameters...
When you construct the Collection, pass the id as parameter (by default, Collection do not have an id property while Model do).
Then, override the url property of the Collection and pass a function:
MyCollection = Backbone.Collection.extend({
initialize : function(models, options) {
this.id = options.id;
},
model : // Your Model class
url: function() {
return '/api/categories/?id=' + this.id;
}
});
// [] is the initial, empty set of models
var coll = new MyCollection([], { id: 45 });
coll.fetch(); // the correct url will be called

Backbone JS Models and Collection URLs

If I have a model named "Book" and a collection named "Library" defined as below:
Book
app.Book = Backbone.Model.extend({
defaults: {
title: 'No title',
author: 'Unknown'
}
});
Library
app.Library = Backbone.Collection.extend({
model: app.Book,
url: '/api/books'
});
When I call BookInstance.save() how does it come up with the URL to use? Does it derive it from the collection?
In Backbone.model there are 2 options: url and urlRoot. What is the purpose and difference between these?
In Backbone.collection, there is a single parameter url. Is this always the GET request for the RESTFUL api?
Basically, there are 3 possibilities to construct a model's url:
If the model object exists in a collection then its url method will return an address composed of the collection.url and model.id: [collection.url]/[id].
If you don't want to use a model inside the collection, then model.urlRoot's value can be used instead of the collection.url fragment, resulting in the following pattern: [urlRoot]/[id].
Finally, if you're NOT planning to persist more that one model of a given type to the server or will be defining URLs for each model upon their creation, you can directly assign a value to model.url.
Collections send only GET requests — to get an array of models' JSON data. For saving, removing, and updating, the individual model's save() (POST/PUT/PATCH) and destroy() (DELETE) methods are used.
Here's the source code of Backbone.Model.url, which should help you:
url: function() {
var base =
_.result(this, 'urlRoot') ||
_.result(this.collection, 'url') ||
urlError();
if (this.isNew()) return base;
var id = this.get(this.idAttribute);
return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
}
In model
urlRoot is used for the Model.
url is used for the instance of the Model.
So if urlRoot exists
then book.fetch() will fetch the data given id, for example
var Book = Backbone.Model.extend({urlRoot: 'books' });
var book = new Book({id: 1});
book.fetch(); // will get /books/1
var Book = Backbone.Model.extend({});
var book = new Book({url: 'books/1'});
book.fetch(); // will get /books/1
var Books = Backbone.Collection.extend({model: Book});
var books = new Books({ /*....*/ });
books.fetch(); // will get /books/
You can refer the backbone Model urlRoot source code here
I hope it makes sense to you, good luck.

How to initialise nested Backbone.js models

In my Application, I have the following JSON data format:
{
Item: {
property1: '',
...
}
}
Following the solution of this stackoverflow.com answer, I modeled my Backbond.js models the following way:
App.Models.Item = Backbone.Model.extend({
});
App.Models.ItemData = Backbone.Model.extend({
defaults: {
'Item': new App.Models.Item
}
});
I now want to bootstap the data to my App from the Backend system on the page load the following way:
var item = App.Models.ItemData({
{Item:
{property1: 'data'}
}
});
The problem I have now is that item.get('Item') returns a plain JavaScrip object and not a Backbone.Model object, because the defaults are overwritten. How can I create the Backbone.js object while ensuring that item.get('Item') is an App.Models.Item object?
I also have read that if you nest Backbone.Models, you should wirite custom getter methods, so the rest of your app dose not have to know about the internal data structure. If so, what is the right way to implement those setters and getters?
You can override the parse method on your ItemData model. No defaults required. The parse method will initialize an empty model, if one is not passed:
App.Models.ItemData = Backbone.Model.extend({
parse: function(attrs) {
attrs = attrs || {};
if(!(attrs.Item instanceof App.Models.Item))
attrs.Item = new App.Models.Item(attrs.Item);
return attrs;
}
});
And then initialize your ItemData model with the option parse:true:
var item = new App.Models.ItemData({Item:{property1: 'data'}}, {parse:true});

Resources