In my view - after I fetch the data from collection, I am trying to loop the models using "native" - each method, but I am getting an error:
Uncaught TypeError: Object [object Object] has no method 'each'
still I am able to convert my models to json objects..
console.log(models.toJSON()); // giving result
models.each(function(model){
console.log(model); // throw the error.. why..?
})
Here is the part of the view where I am consoling:
initialize:function(){
var that = this;
this.collection = headerCollection;
this.listenTo(this.collection, "add", this.addAll);
this.collection.fetch();
},
addAll:function(models){
models.each(function(model){
console.log(model);
})
console.log(models.toJSON());
},
What would be the issue?
If you look at the Catalog of events in docs, it says that arguments being passed to collection's add event handler are (model, collection, options), so model won't have each method with it. May be you can listen to reset event as the arguments being passed for that are (collection, options).
Then you should be able to do models.each in addAll method.
It does not look like the collection is passed to your addAll method as an actual collection but as an array?
What does console.log(typeof models) do?
If you bind the eventhandler to this you can access the collection that way.
initialize:function(){
var that = this;
this.collection = headerCollection;
this.collection.on("add", this.addAll, this);
this.collection.fetch();
},
addAll:function() {
this.collection.each(function(model){
console.log(model);
})
console.log(this.collection.toJSON());
},
I am not familiar with the listenTo method so I don't know what that does.
Related
I created a view, that's listening to a collection. The models of this collections get replaced all at once. I want the view to be rendered as rarely as possible.
View:
BoxContent = Backbone.View.extend({
initialize: function(options) {
console.log("BoxContent initializing");
this.el = options.el;
this.collection = options.collection;
this.collection.on("add", this.update, this);
this.collection.on("reset", this.update, this);
},
update: function(){
this.render();
},
render: function() {
document.getElementById('boxContentHeader').innerHTML = localStorage.activeBox;
console.log("BoxContent rendering");
var temp = _.template(maincontemp,{boxFolder: this.collection});
this.$el.empty();
this.$el.append(temp);
this.$el.trigger("create");
},
reset: function()
{
this.render();
},
close: function(){
//console.log("off-logging clickListener");
//this.collection.off();
//$(this.el).off();
}
});
To update the collection I create an array of models, reset the collection and put the new array to the collection. I need to listen to reset, to make an empty collection beeing rendered.
I don't fetch the data from a restful-server.
Are there other ways to listen to changes to the collection?
EDIT:
One more question: Although I just add one array of models to the collection, is backbone calling the add event for each of the models inside of this array?
Take a look at the Catalog of Events in the docs. You can listen to all of the events which have the argument collection in the arguments.
add - (model, collection, options) — when a model is added to a collection.
remove - (model, collection, options) — when a model is removed from a collection.
reset - (collection, options) — when the collection's entire contents have been replaced.
sort - (collection, options) — when the collection has been re-sorted.
destroy - (model, collection, options) — when a model is destroyed.
request - (model_or_collection, xhr, options) — when a model or collection has started a request to the server.
sync - (model_or_collection, resp, options) — when a model or collection has been - successfully synced with the server.
error - (model_or_collection, resp, options) — when model's or collection's request to remote server has failed.
all – this special event fires for any triggered event, passing the event name as the first argument.
I am following the tutorial at:
http://arturadib.com/hello-backbonejs/docs/3.html
This is a piece of code I am stuck on:
initialize: function(){
_.bindAll(this, 'render', 'addItem', 'appendItem'); // remember: every function that uses 'this' as the current object should be in here
this.collection = new List();
this.collection.bind('add', this.appendItem); // collection event binder
this.counter = 0;
this.render();
},
The line of code that I am having a hard time understanding is:
this.collection.bind('add', this.appendItem);
I know there is a bind method in underscore, but I don't think that is the same bind function.
Could you explain what the above line is for and where I can read more about it?
In backbonejs, a collection can trigger events. Example:
this.collection.trigger('myEvent');
In addition, you can also bind a collection to some events. Example:
this.collection.bind('myEvent', function() { ... });
Backbone.Collection.bind() method comes from Backbone.Events. Note that Backbone.Collection has all the methods of Backbone.Events mixed in (like all the other backbone.js objects including Backbone itself).
Backbone.Events.bind() is an alias for Backbone.Events.on().
I'm creating an application for Phonegap using Backbone framework and Parse.com as backend service. I create an object with Parse.com (corresponding to Backbone models).
This object has a saveDraftToP() method that calls the Parse.com function save().
After this method is called from a view, I'd like to retrieve the updated object.
To do so I'm binding the 'change' event to the model but the Parse assigned ID is undefined.
Here is the code of the model:
var Match = Parse.Object.extend("Match", {
states: {'DRAFT': 0, 'RUNNING': 1, 'ENDED': 2},
saveDraftToP: function () {
var self = this;
this.save({
user: Parse.User.current(),
ACL: new Parse.ACL(Parse.User.current()),
state: self.states.DRAFT
}, {
success: function (result) {
self = result;
},
error: function (e) {
}
});
}
});`
And here is the code for the view:
var vmNuovaPartita = Parse.View.extend({
template: Handlebars.compile(template),
model: new Match(),
collection: new HintCollection(),
initialize: function () {
this.bind("change:model", console.log(this.model.id) , this);
},
render: function (eventName) {
var match = this.model.toJSON();
$(this.el).html(this.template(match));
return this;
}
});
I'm not quite sure why you have a save function wrapped in another save-like function. :-)
Say you have something like myMatch which is an object.
Through your UI, a button click saves the object data. You can just use myMatch.save({attr:val, ...}) straight out of the box. Backbone (and Parse) by default are optimistic. That means, you it will set the values of the model with the expectation that persisting to the server will succeed.
Thus, you don't need to retrieve anything extra. You already have the model in it's most current state.
To have a model view that responds to these changes, I'd design the view a little differently.
var vmNuovaPartita = Parse.View.extend({
template: Handlebars.compile(template),
initialize: function () {
this.model.on('change', this.render);
},
render: function (eventName) {
var match = this.model.toJSON();
$(this.el).html(this.template(match));
return this;
}
});
var myView = new vmNuovaPartita({
model: myModel
});
I'd initialize the model outside of the view, then pass it in as an option when you generate a new view. When you pass a model in as an option, it's special and will be attached directly to the view ... view.model which you can refer inside your view code as this.model
In the init we place a listener on the model for change events, then fire off a rerender of the view. Or a nicer way to go about this sort of thing is to throw in the newer Backbone Events with the .listenTo() method.
I have a User model in a Backbone application that makes an ajax request. In the error callback, I wish to set an error message to pass to the view. However, if I try do
this.set({errors: result.errors});
I'm told "this" doesn't have a method set. In this case, I believe "this" is the ajax response object (rather than the User model which does have a set method)
Object {url: "/users.json", isLocal: false, global: true, type: "POST", contentType: "application/x-www-form-urlencoded; charset=UTF-8"…}
However, I also tried to do
this.model.set({errors: result.errors});
but it said I can't call "set" of undefined. I'm assuming it doesn't make sense to say "this.model" from within the model, but, as mentioned above, if I just say "this," it refers to the response object.
Is this the wrong way to go about it?
I am assuming you are doing something like this when you are saving your model
model.save({
success: function() {},
error: function() {
this.set({ errors: result.errors });
}
});
If that is the case, then you can change this.set to model.set, and everything will work.
However it doesn't really make that much sense to be storing the error message as a model attribute.
The model will fire an event when its save call fails on the server (check out the backbone events catalogue).
Therefore if you have a view with an attached model, you can tell the view to listen to this error event.
var MyView = Backbone.View.extend({
initialize: function() {
// if your using backbone v0.9.10
this.listenTo(this.model, 'error', this.handleModelError);
// or for earlier versions
this.model.on('error', this.handleModelError, this);
},
handleModelError: function(model, xhr, options) {
// show an error message, or whatever
}
});
var view = new MyView({ model: aModel });
// if the server returns an error, view.handleModelError will be called
aModel.save();
I think this probably loses context. Try using var self = this. Something like:
var self = this;
model.save("author", "F.D.R.",
{error: function()
{
self.model.set({errors: result.errors});
}});
I'm having a look at Backbone.js, but I'm stuck. The code until now is as simple as is possible, but I seem not to get it. I use Firebug and this.moments in the render of MomentsView is an object, but all the methods from a collection don't work (ie this.moments.get(1) doesn't work).
The code:
var Moment = Backbone.Model.extend({
});
var Moments = Backbone.Collection.extend({
model: Moment,
url: 'moments',
initialize: function() {
this.fetch();
}
});
var MomentsView = Backbone.View.extend({
el: $('body'),
initialize: function() {
_.bindAll(this, 'render');
this.moments = new Moments();
},
render: function() {
_.each(this.moments, function(moment) {
console.log(moment.get('id'));
});
return this;
}
})
var momentsview = new MomentsView();
momentsview.render();
The (dummy) response from te server:
[{"id":"1","title":"this is the moment","description":"another descr","day":"12"},{"id":"2","title":"this is the mament","description":"onother dascr","day":"14"}]
The object has two models according to the DOM in Firebug, but the methods do not work. Does anybode have an idea how to get the collection to work in the view?
The problem here is that you're fetching the data asynchronously when you initialize the MomentsView view, but you're calling momentsview.render() synchronously, right away. The data you're expecting hasn't come back from the server yet, so you'll run into problems. I believe this will work if you call render in a callback to be executed once fetch() is complete.
Also, I don't think you can call _.each(this.moments) - to iterate over a collection, use this.moments.each().
Try removing the '()' when instantiate the collection.
this.moments = new Moments;
Also, as it's an asynchronous call, bind the collection's 'change' event with the rendering.
I hope it helps you.