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
Related
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;
});
}
});
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.
I want to retrieve a collection of keywords of a file with an POST request like this:
api.host.com/file/4/keywords
But how do I have to define my url and urlRoot Keyword model and keyword collection?
I've read the docs, but I could not figured it out.
As usual, in general but especially in JS, there are many ways to do that. I can tell you a couple of ways I would do that.
1) I would define a keywords Collection as
Keywords = Backbone.Collection.extend( { ... } )
Then use it as a property of the File Model and I would set the correct value during initialize()
File = Backbone.Model.extend({
// the empty array [] is the initial set of models
this.keywords = new Keywords([], { url: '/file/' + this.id + '/keywords' });
})
This way you can call file.keywords.fetch() to get the content.
2) I would define a keywords Collection as
Keywords = Backbone.Collection.extend({
initialize: function(models, options) {
this.modelId = options.modelId
},
url: function() {
return '/file/' + this.modelId + '/keywords'
}
});
And then, when needed, I would create instance like this:
File = Backbone.Model.extend({
this.keywords = new Keywords([], { modelId: this.id });
})
To give you a complete answer, you could actually drop the initialize() function (if you don't need it) and write and url function as
url: function() {
return '/file/' + this.options.modelId + '/keywords'
}
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.
My model is structured like this:
model = {
distance: 12.05,
widget: {
id: 1,
creationDate: '12/01/2012'
}
}
How do I set the idAttribute of the model to be the id on the widget property? Is there a syntax to do this?
How about rearranging/flattening your model to make id a top-level property? Override parse and you won't need to set the idAttribute:
var YourModel = Backbone.Model.extend({
parse: function (response) {
var distance = response.distance;
response = response.widget;
response.distance = distance;
return response;
}
});
Now id will be automatically picked up by Backbone as the id. If you need to persist your data back to your datastore, you'll need to overwrite methods necessary to transform the data back. If possible, it would be a better solution if your model came structured with id already at a top level.