i am facing problem in backbone collection.
this is my router
var LanguageRouter = Backbone.Router.extend({
routes: {
'': 'defaultaction',
'section/:key': 'sectionview',
}
});
collection is
var LanguageCollection = Backbone.Collection.extend({
model: LanguageModel,
url: '/lang'
});
and app.js
var initialize = function () {
var language_router = new LanguageRouter(),
parent_view = new ParentView(),
list_collection = new LanguageCollection(),
list_collection.fetch();
language_router.on('route:defaultaction', function () {
list_view = new LanguageListView({
collection: list_collection,
template: _.template(templates.languagelistsingle)
});
});
Here , after fetching the list_collection i tried passed the collection to language_view but i am getting empty collection only. How to fix this... Thanks in advance
Fetch is not synchronous, so you cannot call it in one line and use the return on the next line. The correct way using backbone is use listenTo or On (depending on the backbone version)
You could change this part:
list_collection = new LanguageCollection();
this.listenTo(list_collection, "sync", this.someFunction());
\\here we are listening the sync event that is automatically fired by backbone when a model or collection is synced with the server.
list_collection.fetch();
someFunction:function(){
//Logic with the collection content...
}
To learn more about events, please take a read here: http://backbonejs.org/#Events-catalog
Related
I am new to Backbone.js so please bear with me.
I have the following code that correctly fetches JSON onSearchClicked. I can see the JSON in the console view. I would like to render the retrieved responseJSON to a view or pass the data through an existing model (under car_view.js) - so I can view on a HTML page. How can I do this?
Any help much appreciated.
view.js
--------------
var View = Backbone.View.extend({
tagName: 'div',
ranking: 0,
events:{
'click .search-button': 'onSearchClicked'
},
onSearchClicked : function(){
var searchString = $('.search-field input').val();
$('#gallery ul').empty();
var search = new carCollection([], {query: searchString});
search.fetch( {success: this.searchResults.bind(this) });
console.log(search.fetch());
},
},
search_collection.js
--------------
var Backbone = require('backbone');
var BurgerModel = require('../models/car');
var CarCollection = Backbone.Collection.extend({
model:CarModel,
initialize : function(models, options){
this.query = options.query;
},
url: function(){
return "/api/cars?name="+this.query;
}
});
module.exports = CarCollection;
car_view.js
--------------
carCard: function( burger ){
var carView = new CarView({
model: car
});
this.$el.append( carView.el );
},
There is a typo - Make 'C' capital in this line:
var search = new carCollection([], {query: searchString});
I am not going to provide the working code but I can provide you steps:
Please create a new class CarList which should have a reference to CarCollection
When User enters search query, a method of CarList should be invoked in which you should call fetch of collection
In success callback of fetch invoke a method renderCars
Inside renderCars For each search result create an instance of CarView and render it in an element.
Hope this is what you want. If you are looking for exact code, then nobody is going to help you on SO!!
var Router = Backbone.Router.extend({
routes:{
'notes': 'showNotes',
"note/:noteId": "openNote"
},
showNotes: function() {
new app.NotesView;
},
openNote: function(noteId) {
var NotesCollection = new app.NotesCollection();
NotesCollection.fetch();
var view = new app.NotesView({
currentModel : NotesCollection.get(noteId)
})
}
});
Here the problem comes when I navigate to domain.com/#notes every time I navigate there a double view occurs, and any event get's fired multiple times.
I think it's because every time you go there, you create a new view (the old view still exists). Instead, can you just create the view once and on showNotes, you call render?
Also, as a side note, fetch() is an asynchronous call so you have to wait until data is fetched by passing in a callback (success function) and doing your calculations there.
Something like this:
var notesView = new app.NotesView;
var Router = Backbone.Router.extend({
routes:{
'notes': 'showNotes',
"note/:noteId": "openNote"
},
showNotes: function() {
notesView.render(); // or append notesView.$el into the dom somewhere
},
openNote: function(noteId) {
var NotesCollection = new app.NotesCollection();
NotesCollection.fetch({
success: function(){
notesView.setModel(NotesCollection.get(noteId); // make this method youself
}
});
}
});
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'm trying to add a list of models to a collection to be stored locally. I don't fully understand backbone yet which is really the cause of this problem.
I basically pull in an RSS feed, assign each item in the feed to a Model and try place the list of Models into a collection so I can iterate over them later.
I am getting an error saying that I need to specify a Url for the collection.
It would be brilliant if someone could explain to me the correct process I need to follow to achieve my goal.
Currently I have:
var DetailIndividual = Backbone.Model.extend();
var DetailsIndividual = Backbone.Collection.extend({
model: DetailIndividual
});
var Search = Backbone.View.extend({
events: {
'click a.individualCast' : 'pullIndividual'
},
initialize: function() {
this.detailsIndividual = new DetailsIndividual();
_this = this;
this.detailsIndividual.bind('reset', function(collection) {
collection.each(function(item) {
//code to handle update
});
});
},
pullIndividual: function(e){
e.preventDefault();
//Logic to pull in RSS feed
for (var i = 0; i < result.feed.entries.length; i++) {
entry[i] = new DetailIndividual({ title: result.feed.entries[i].title, link: result.feed.entries[i].link, });
}
this.detailsIndividual.add(entry);
}
});
The error is reported out from here,because model must have url attribute:
http://backbonejs.org/docs/backbone.html#section-167
do you model have url attribute?
The reason why you're getting the error is because you're binding the 'reset' event. 'reset' is only fired on a collection.fetch or an explicit call to collection.reset, and in your case you're never fetching from the server with your collection - I'm assuming from your code you already have the feed in memory - so unless you're explicitly resetting, there's no need to listen for the reset.
In your code, you're not really extending Collection and Model, so it's actually not necessary to make extended objects - just use Backbone.Collection. You don't even need to create a Model extension because by default, when you add a JSON, a Backbone.Model is automatically created. It's only necessary to assign the collection.model if you're creating a truly custom model (with method overrides and additions).
Here's a way you could load your collection:
var search = Backbone.View.extend({
events: {
'click a.individualCast' : 'pullIndividual'
},
initialize: function() {
this.detailsIndividual = new Backbone.Collection();
},
pullIndividual: function(e) {
e.preventDefault();
//Logic to pull in RSS feed
for (var i = 0; i < result.feed.entries.length; i++) {
this.detailsIndividual.add({
title: result.feed.entries[i].title,
link: result.feed.entries[i].link
});
}
}
});
You didn't provide any code of how you wanted to parse collection (except in the 'reset'), but essentially you'd load the collection from the feed as shown.
I need to pass an id to a collection for use in the url (e.g. /user/1234/projects.json) but am not sure how to do this, an example would be wonderful.
The way my application is structured is on launch a collection of 'users' is pulled and rendered, I then want when a user is clicked their 'documents' are pulled from the server into a new collection and rendered in a new view. The issue is getting the user id into the documents collection to give the relevant URL for the documents.fetch().
think I've got it, here is an example:
//in the the view initialize function
this.collection = new Docs();
this.collection.project_id = this.options.project_id;
this.collection.fetch();
//in the collection
url: function() {
return '/project/api/' +this.project_id+'/docs';
}
Your user collection url should be set to /user. Once that's set, your models should utilize that url in order to do their magic. I believe (not completely positive) that if a model is in a collection, calling the 'url' method will return /user/:id. So all your typical REST-ish functionality will be utilized on '/user/:id'. If you are trying to do something with a relationship (a user has many documents) it's kind of rinse and repeat. So, for your documents collection (which belogs to user correct?) you'd set the url to 'user_instance.url/documents'.
To show a one to many relationship with a backbone model, you'd do something like this (upgrade to backbone 0.5.1 for urlRoot):
var User = Backbone.Model.extend({
initialize: function() {
// note, you are passing the function url. This is important if you are
// creating a new user that's not been sync'd to the server yet. If you
// did something like: {user_url: this.url()} it wouldn't contain the id
// yet... and any sync through docs would fail... even if you sync'd the
// user model!
this.docs = new Docs([], {user_url: this.url});
},
urlRoot: '/user'
});
var Doc = Backbone.Model.extend();
var Docs = Backbone.Collection.extend({
initialize: function(models, args) {
this.url = function() { args.user_url() + '/documents'; };
}
});
var user = new User([{id: 1234}]);
user.docs.fetch({ success: function() { alert('win') });
Why do you need to override the URL property of the collection with a function?.. you could do:
this.collection = new Docs();
this.collection.project_id = this.options.project_id;
this.collection.url = '/project/api/' + this.options.project_id + '/docs';
this.collection.fetch();
I like the answer from Craig Monson, but to get it working I needed to fix two things:
Binding the User url method before passing it to the Docs
A return statement from the url function in Docs
Updated example:
var User = Backbone.Model.extend({
initialize: function() {
// note, you are passing the function url. This is important if you are
// creating a new user that's not been sync'd to the server yet. If you
// did something like: {user_url: this.url()} it wouldn't contain the id
// yet... and any sync through docs would fail... even if you sync'd the
// user model!
this.docs = new Docs([], { user_url: this.url.bind(this) });
},
urlRoot: '/user'
});
var Doc = Backbone.Model.extend();
var Docs = Backbone.Collection.extend({
initialize: function(models, args) {
this.url = function() { return args.user_url() + '/documents'; };
}
});
var user = new User([{id: 1234}]);
user.docs.fetch({ success: function() { alert('win') });