I want to trigger a backbone event when the view has rendered. Ideally, I'd write something like this:
var DetailView = Backbone.View.extend({
id: 'detailpage',
events: {
'ready document': '_bringSlideDown',
'click .close-slideDown': '_closeSlideDown'
},
and I would be able to create and call a _bringSlideDown function once the view has finished loading. This doesn't work - is there a better way to call this event?
Specifically, I want the event to only run once, which is why I'm not nesting it in the render function. I want the view to be able to render multiple times, but want to use Backbone's .off() method to handle this event once before unbinding it. Thanks!
I have three points that I want to mention.
First, by best practice I execute Backbone code until the DOM is
ready, so if you follow this rule, your backbone view will be
executed after the DOM was ready(so there is no way to listen for the ready event).
If you want to listen for DOM additions with jQuery, you should use
plugins like: https://github.com/brandonaaron/livequery
Regarding your use case, instead of listen to the DOM, check in the render
method if is the first time that you are rendering the view using
a flag.
I would do something like this:
var YourView = Backbone.View.extend({
_rendered : false,
events : {
'click .close-slideDown': '_closeSlideDown'
},
render: function(){
//some render stuff
if( !this._rendered ){
this._rendered = true;
this._bringSlideDown();
}
}
});
Basically
Related
I'm new to backbone. I have been looking it has been used in Saiku. I came across the below line.
Saiku.session.trigger('workspace:new', { workspace: this });
Is 'workspace:new' an event? How does backbone trigger recognize it as an event?
Short answer: yes, workspace:new is an event.
Backbone has several built-in events that you can listen for. But you can also trigger custom events, as this code does. The event is identified by only a string (in this case, "workspace:new"). When you call trigger on an object that inherits from Backbone's Event Module, that event "happens." As a second parameter to trigger, you can pass some data about the event, anything you want accessible from the event handler function.
Then, usually somewhere else, there will be code waiting for that event to happen. That is set up by calling the .on or .listenTo methods.
Here's a basic example: (See it in action on JSBin)
var model = new Backbone.Model();
model.on('my-event', function (data) {
console.log("my-event happened!");
console.log(data);
});
model.trigger('my-event');
model.trigger('my-event', 'some-data');
model.trigger('my-event', { anything: 'works' });
I have the following listener in the view for when a model is changed:
this.listenTo(this.model, 'change', this.render);
When I change the model :
model.set('foo', bar);
Is it possible to make it not trigger the listener event for this specific function call? I still want the event to trigger at other calls.
From the fine manual:
Generally speaking, when calling a function that emits an event (model.set, collection.add, and so on...), if you'd like to prevent the event from being triggered, you may pass {silent: true} as an option. Note that this is rarely, perhaps even never, a good idea. Passing through a specific flag in the options for your event callback to look at, and choose to ignore, will usually work out better.
So if you don't want that specific set call to trigger a change event then:
model.set('foo', bar, { silent: true });
Or tunnel some information to render using a custom option:
model.set('foot', bar, { ignore_this: true });
and adjust render:
render: function(options) {
if(options && options.ignore_this)
return;
// ...
}
Good day to all.
I'm writing an application using Marionette.js and recently I started noticing that moving from view to view and starting/stopping different modules memory consumption grows and not getting released. I started wondering whether I unbind my events correctly and whether I bind to them correctly as well.
So, I have the following cases
Modules
My application consists of sub-applications (modules). When I define a module I do some binding to global event aggregator. Something like this:
MyApplication.module(...) {
var api = { ... some functions here ... }
// Binding to events
MyApplication.vent.on('some:event', function() {...});
MyApplication.vent.on('some:other:event', function() {...});
}
I have checked the documentation and understand that "on" is not a very good choice, I should probably use "listenTo":
MyApplication.module(...) {
var api = { ... some functions here ... }
// Binding to events
this.listenTo(MyApplication.vent, 'some:event', function() {...});
this.listenTo(MyApplication.vent, 'some:other:event', function() {...});
}
But, here is the question, when module gets stopped, does it call "stopListening" or some other internal method that unbinds all the events I have bound in it? I checked the source code of the marionette's module and documentation but, if I understood correctly, when stop is called I need to take care of unbinding everything myself. Am I right?
Controllers
Can be initialized and closed. From the documentation I see that:
Each Controller instance has a built in close method that handles unbinding all of the events that are directly attached to the controller instance, as well as those that are bound using the EventBinder from the controller.
Does it mean that if do the following I correctly unbind all of the events I bound in the controller? I guess the answer is yes.
MyApplication.module(...) {
var controller = Marionette.Controller.extend({
...
// This will be unbinded as I understand?
this.listenTo(someObject, 'some:event', _.bind(function() {
// This will also be unbinded
this.listenTo(someOtherObject, 'some:event', function() {
// This won't be, because in this case this is not in a "controller"
// context but in a function's context which wasn't bound to "controler"
// context.
this.listenTo(some3rdObject, 'some:event', function() { ... });
});
}, this));
});
// Create controller when this sub-application gets initialized.
Contents.addInitializer(function () {
MyModule.Controller = new controller();
});
// Destroy controller and unbind all its event handlers.
Contents.addFinalizer(function () {
MyModule.Controller.close();
delete Contents.Controller;
});
}
So, with controllers I don't need to do anything as long as I use "listenTo", correct?
Views
In views, according to documentation, all gets unbinded when the view gets closed. And again, as long as I use
this.listenTo(..., 'some:event', function() {...});
I should be ok, correct?
To summarize... I only need to take care of unbinding in module's stop event, in all other cases it is taken care of by marionette's core as long as I don't use direct "on" and use "this.listenTo" instead.
Thank you all very much in advance for your answers.
Controllers and Views do their cleaning work correctly but Modules doesn't do it.
Here is more detailed info:
Controller
If you close controller it will unbind all events that are bonded using listenTo in context of controller. You can look in in controller source code.
View
According to Backbone.View source code remove method does stopListening. Also Marionette.View's close calls backbone's remove under the hood. Here is source code.
Module
I've checked Marionette.Module source code but there is no stopListening in stop method. So, Marionette.Module#stop does not do unbinding of events and you should do it manually in finalizer or in onStop, onBeforeStop handlers.
UPDATED: After Marionette.js v1.7.0 Marionette.Module calls stopListening on stop to unbind all events.
I wanna know if there is anyway to depend event binding with "if" in Backbone.
For example, if i have user profile model and i want to bind "Send Message" button event only if the attribute "acceptMsgs" sets true.
My current solution is to check it in the event firing, if there is better way, pls correct me.
I'm not sure if it's a better way to do it, but you can use a function that returns a hash for the event hash (and of course in the function you can check for some condition).
For example something along the lines of
myView = Backbone.Views.extend({
events: function () {
if (someCondition) {
return { "#someButton click" : "nameOfFunction"}
}
}
//the rest of your view
});
Alternatively you can forgo the event hash and bind your events in the initialize method, for example
initialize: function (options) {
if (someCondition) {
this.$el.on("click", "#someButton", nameOfFunction);
}
}
I want to validate a users input by keydown. For this I require a keydown event.
Unfortunatly I only have found custom model events:
initalize: function(){
this.model = new ModelClass();
this.model.bind("keydown", this.validate, this);
}
That approach surely is fine for model events but I don't believe this is the right way for view, ui-related stuff...
To give you a better explication, this is how I would like to use my event:
var SomeView;
SomeView = Backbone.View.extend({
events: {
"keydown input#some-field": "validate" // custom event
, "change input#some-field": "doSomethingElse" // predefined backbone event
},
validate: function(attr){
// validation
}
});
So what is the approach to create custom Backbone Events which are callable in the View?
what is the approach to create custom Backbone Events which are callable in the View?
I feel as if your problem is not a problem,because backbone.view default has been to support the events.
you can write code like what you want to:
//This is the right thing to do
SomeView = Backbone.View.extend({
events: {
"keydown input#some-field": "validate" // custom event
, "change input#some-field": "doSomethingElse" // predefined backbone event
},
validate: function(attr){
// validation
}
});
Reference here:
http://backbonejs.org/docs/todos.html#section-22
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDIT :
you can see here:
http://backbonejs.org/docs/backbone.html#section-156
The most critical sentence is:
this.$el.delegate(selector, eventName, method);
because backbone's events is jquery's delegate(http://api.jquery.com/delegate/),so jQuery's delegate to support the event, backbone are available.
I'm not sure I'm understanding what the problem is. Your second example is definitely how I would and have gone about setting up event handlers in Backbone Views. Backbone's validate method only exists in the model and is called automatically before the models set and save are called. It is left undefined as default. If you are validating in the view though your way should work. But i believe event handling functions are only passed the event. so it should probably be
validate: function (event) {
// do Something here
}
also you should keep in mind that backbone event delegation takes place in the el. so you will need to either set it manually or render into it in order for event delegation to to work