'Backbone.js: Custom subscribing and publishing custom event between views / models
This is my case: I use jQuery.Forms to make an ajax call out of submitting a form. When the ajax call starts and returns, I need various Models / Views to respond to those events (the Model updates with data returned from the call, some controls are disabled and then enabled and so on).
I have the form mapped within a View. How can I trigger a custom formSubmitting "formSubmitted (with data)" even from the view and have any number of Models / Views responding to those events? What is the most idiomatic way of doing this with Backbone.js?
EDIT:
This is what I'm trying to do:
window.UploaderView = Backbone.View.extend({
initialize: function() {
this.setElement(this.options.base_div);
this.$el.find('form').ajaxForm({
beforeSubmit: function() {
this.trigger('ajax-calling');
},
success: function(responseJSON) {
this.trigger('ajax-called', responseJSON);
},
dataType: 'json,'
});
},
});
var update_uploader = new window.UploaderView({
base_div: $('#update-upload-action'),
});
var trigged = new window.UploaderView({
parent_view: update_uploader,
initialize: function() {
this.options.parent_view.on('ajax-calling', function() {
alert('calling!');
});
},
});
But this does not work (no alert message is shown).
Solution 1:[1]
Your initialize function is never executed when your create new window.UploaderView instance, it is placed in view's options instead (see Backbone.js View construction documentation).
What you need is an event bus, single object inherited from Backbone.Events and available for all your views/models:
var eventBus = _.clone(Backbone.Events);
window.UploaderView = Backbone.View.extend({
initialize: function() {
this.setElement(this.options.base_div);
this.$el.find('form').ajaxForm({
beforeSubmit: function() {
eventBus.trigger('ajax-calling');
},
success: function(responseJSON) {
eventBus.trigger('ajax-called', responseJSON);
},
dataType: 'json,'
});
},
});
window.AnotherView = Backbone.View.extend({
initialize: function() {
eventBus.on('ajax-calling', this.ajaxCallingHandler);
},
});
window.AnotherModel = Backbone.Model.extend({
initialize: function() {
eventBus.on('ajax-called', this.ajaxCallingHandler);
},
});
P.S. Please also note that ajaxForm success and beforeSubmit handlers in your example are executed with the scope of the ajax settings object. So you can't just use this.trigger() in them and would have to either bind these functions to window.UploaderView with _.bind() or use a closure. More on scope binding.
Solution 2:[2]
The AJAX response is out of the scope of the view so "this" does not belongs to the view. Moving the responses to the view and applying _.bindAll(this); fixes your issues.
window.UploaderView = Backbone.View.extend({
initialize: function() {
_.bindAll(this);
this.setElement(this.options.base_div);
this.$el.find('form').ajaxForm({
beforeSubmit: this.onBeforeSubmit,
success: this.onSuccess,
dataType: 'json,'
});
},
onBeforeSubmit : function() {
this.trigger('ajax-calling');
},
onSuccess: function(responseJSON) {
this.trigger('ajax-called', responseJSON);
}
});
var update_uploader = new window.UploaderView({
base_div: $('#update-upload-action'),
});
var trigged = new window.UploaderView({
initialize: function() {
this.options.parent_view.on('ajax-calling', function() {
alert('calling!');
});
},
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | vvd |
| Solution 2 |
