var BasicModel = Backbone.Model.extends({
url : function() {
return "/something";
}
});
var basicModel = new BasicModel();
basicModel.fetch();
If BasicModel is a collection, then the follwoing is possible
this.on("add", function (model) {
console.log(model);
});
Is there any lisiting event I can bind for Backbone model, which get invoked after fetch happened?
use change event.
in your model.
this.on("change", function);
or in your view
this.model.on("change", function);
basicModel.fetch({success:function(){
//do whatever you want
}});
Related
I have this collection with an over-riden parse method. I want a method in my view to be called when the collection is finished with parse
This collection will be calling sync and so parse only once.
I tried this.collection.on("reset", this.more, this); but that doesn't work.
more: function() {
var users = this.collection.slice( this.index, this.index + this.load_once), that = this;
this.index = this.index + this.load_once;
_.each( users, function( user ){
that.addOne( user );
});
},
addOne: function( user ){
var view = new UserView({model: user});
this.$("#user_list").append(view.render().el);
}
The reset method will be triggered when {reset: true} option is passed to the fetch. You can listen to the add and sync that will fire this method. Also use this.listenTo bind the events in a cleaner manner.
initialize: function() {
... some other code
this.listenTo(this.collection, "add sync", this.more);
this.collection.fetch();
}
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.
In my backbone function, while the name get change the change function not at all triggering.. any one suggest me the right way to get it.. (actually i need to get changed stuff and need to update);
code :
(function($){
var list = {};
list.model = Backbone.Model.extend({
defaults:{
name:'need the name'
},
initialize:function(){
this.bind('change:name', function(model) {
console.log('Model->change()', model);
});
}
});
list.collect = Backbone.Collection.extend({
model:list.model,
url : 'data/names.json',
initialize:function(){
this.fetch({update:true});
this.keepUpdate();
},
keepUpdate:function(){
var that = this;
var updateData = function(){
that.fetch({update:true});
myTimeout = setTimeout(updateData,10000);
}
var myTimeout = setTimeout(updateData,10000);
}
});
list.view = Backbone.View.extend({
initialize:function(){
this.collection = new list.collect();
this.collection.on("update", this.render, this);
this.collection.bind("change:name", function(model, attributes){
console.log(model,attributes,'property changed'); // this is not triggering at all..
});
},
render:function(data){
_.each(this.collection.models, function(data){
//console.log(data.get('name')); it works fine
})
},
updateName:function(){
console.log('updated called');
}
});
var newView = new list.view();
})(jQuery)
Collection.fetch doesn't trigger the change event. You only get the reset event. If you need more granular events, consider calling fetch with the options {update:true}.
that.fetch({update:true});
That will trigger change event for every model that was already in the collection, and add if the model was previously not in the collection.
Try removing keepUpdate from the collection and put a setTimeout in the initialize function of the view at the end. I suggest that fetch is called from the view as well as this.collection.fetch() instead of the collection's initialize function. Makes your code more reusable.
I'm not sure I understand your question. What are you trying to achieve ?
I don't think that fetch accepts {add:true} as a parameter (I just checked the source code and it does not appear anywhere).
When fetch completes, it only triggers a reset event (not an add). You should listen to that if you want to do something when the content of the collection changes. You can also simplify listen to change.
In my backbone function, while the name get change the change function not at all triggering.. any one suggest me the right way to get it.. (actually i need to get changed stuff and need to update);
code :
(function($){
var list = {};
list.model = Backbone.Model.extend({
defaults:{
name:'need the name'
},
initialize:function(){
this.bind('change:name', function(model) {
console.log('Model->change()', model);
});
}
});
list.collect = Backbone.Collection.extend({
model:list.model,
url : 'data/names.json',
initialize:function(){
this.fetch({update:true});
this.keepUpdate();
},
keepUpdate:function(){
var that = this;
var updateData = function(){
that.fetch({update:true});
myTimeout = setTimeout(updateData,10000);
}
var myTimeout = setTimeout(updateData,10000);
}
});
list.view = Backbone.View.extend({
initialize:function(){
this.collection = new list.collect();
this.collection.on("update", this.render, this);
this.collection.bind("change:name", function(model, attributes){
console.log(model,attributes,'property changed'); // this is not triggering at all..
});
},
render:function(data){
_.each(this.collection.models, function(data){
//console.log(data.get('name')); it works fine
})
},
updateName:function(){
console.log('updated called');
}
});
var newView = new list.view();
})(jQuery)
Collection.fetch doesn't trigger the change event. You only get the reset event. If you need more granular events, consider calling fetch with the options {update:true}.
that.fetch({update:true});
That will trigger change event for every model that was already in the collection, and add if the model was previously not in the collection.
Try removing keepUpdate from the collection and put a setTimeout in the initialize function of the view at the end. I suggest that fetch is called from the view as well as this.collection.fetch() instead of the collection's initialize function. Makes your code more reusable.
I'm not sure I understand your question. What are you trying to achieve ?
I don't think that fetch accepts {add:true} as a parameter (I just checked the source code and it does not appear anywhere).
When fetch completes, it only triggers a reset event (not an add). You should listen to that if you want to do something when the content of the collection changes. You can also simplify listen to change.
According to Backbone.js documentation:
Whenever a UI action causes an attribute of a model to change, the
model triggers a "change" event; all the Views that display the
model's data are notified of the event, causing them to re-render.
So I suppose that render() method should be bound to "change" event by default. However the following code does not work:
TestModel = Backbone.Model.extend({});
TestView = Backbone.View.extend({
render: function() {
alert('render called');
}
});
var mod = new TestModel;
var view = new TestView({model:mod});
mod.change();
It works only if I add explicit bind call:
initialize: function() {
this.model.bind('change', this.render, this);
}
Does this mean that my understanding of default render() callback is not correct and we should always bind render() callback by hand?
Unless something has changed in the last few months, yes, that is the case. This is a good thing, as it gives flexibility as to when views are rendered/re-rendered (for example, some applications might want to render a view only after a model has been persisted on the server, not necessarily when it changes in the browser). If you want your views to always re-render when a model attribute changes, you can extend the default backbone view with your own base view that binds its render method to the model change event, then extend all your concrete views from that. Ex:
MyView = Backbone.View.extend({
initialize: function() {
Backbone.View.prototype.initialize.apply(this, arguments);
this.model.bind('change', this.render);
}
});
MyConcreteView = MyView.extend({...});
var model = new Backbone.Model({...});
var view = new MyConcreteView({model: model});
model.set({prop: 'value'});
You can redefine the Backbone.View constructor to set the render callback by default after creating a new view using the code beneath:
Backbone.View = (function(View) {
// Define the new constructor
Backbone.View = function(options) {
// Call the original constructor
View.apply(this, arguments);
// Add the render callback
if (this.model != null) {
this.model.bind("change", this.render, this);
} else {
// Add some warning or throw exception about
// the render callback not being triggered
}
};
// Clone static properties
_.extend(Backbone.View, View);
// Clone prototype
Backbone.View.prototype = (function(Prototype) {
Prototype.prototype = View.prototype;
return new Prototype;
})(function() {});
// Update constructor in prototype
Backbone.View.prototype.constructor = Backbone.View;
return Backbone.View;
})(Backbone.View);
Now you can create a new view like so:
view = new Backbone.View({model: new Backbone.Model})