问题
I am working on a Backbone application which is based on a dynamic template . I have a header view, a side panel view and footer view that are dynamically initialized when calling any other view . The problem is I have events on each template view that are not firing. For example i have a button that changes the language in the header view but its event isn't firing.
My header View :
define([ "jquery", "backbone", "text!../../pages/header.html" ], function($,
Backbone, headerTpl) {
var header = Backbone.View.extend({
events : {
"click #enBtn":"swichToEnglish",
"click #frBtn":"swichToFrench"
},
initialize : function(options) {
_.bindAll(this, "swichToFrench","swichToEnglish");
this.render(options.parent);
//$("#enBtn").css("pointer-events","none");
},
render : function(parent) {
this.template = _.template(headerTpl);
$(parent).append(this.template);
return this;
},
swichToFrench:function(){
console.log("switch to frensh");
if(i18n.currentLocal == 'en'){
i18n.currentLocal='fr';
$("#frBtn").css("pointer-events","auto");
this.render(options.parent);
}
},
swichToEnglish:function(){
console.log("switch to English");
if(i18n.currentLocal == 'fr'){
i18n.currentLocal='en';
$("#enBtn").css("pointer-events","auto");
$("#frBtn").css("pointer-events","none");
this.render(options.parent);
}
}
});
return header;
});
The header view is called in the router :
self._header = new Header({parent: $(".main_container")});
Any ideas how to fix this issue. I need to know haw to fire these events Thank You.
回答1:
The reason your event handlers is not firing is because the event handlers are delegated to the views element, but you're appending the template to some other element. Since the target elements are in this template which is not appended the view's el
, the events will never bubble into the handlers delegated to it.
Apart from that, as @mu is too short pointed out, when you do $(parent).append(this.template);
,
this.template
is the template function. You should actually call it with the data to get the template.
and you shouldn't be using global selectors like $('')
and use this.$el.find('')
instead as best practice.
also, options
is only available inside the initialize
method, and is undefined
outside.
Instead of passing the parent into the view and then have it append itself to parent, do that outside the view and make the view independent.
Also declare the template property in the view rather than adding it after the creation as a best practice.
And there's no need to bind the context of event handlers to the view manually, by default the context of event handler will be the view.
Your view should look like:
define([ "jquery", "backbone", "text!../../pages/header.html" ], function($,
Backbone, headerTpl) {
var header = Backbone.View.extend({
initialize : function(options) {
this.render();
},
template: _.template(headerTpl),
events : {
"click #enBtn":"swichToEnglish",
"click #frBtn":"swichToFrench"
},
render : function() {
this.$el.append(this.template(/* pass the data here*/));
//--------^----- this is required for the events to work
return this;
},
swichToFrench:function(){
if(i18n.currentLocal == 'en'){
i18n.currentLocal='fr';
this.$el.find("#frBtn").css("pointer-events","auto");
this.render();
}
},
swichToEnglish:function(){
if(i18n.currentLocal == 'fr'){
i18n.currentLocal='en';
this.$el.find("#enBtn").css("pointer-events","auto");
this.$el.find("#frBtn").css("pointer-events","none");
this.render();
}
}
});
return header;
});
Which you can create like:
self._header = new Header();
$(".main_container").append(self._header.el);
it looks like you just want the view content to be added to '.main_container'
, and doesn't need another element. In that case you can make your views el
point to it rather than creating a new element by passing it as el
in the options like:
self._header = new Header({
el: '.main_container' // this.el will refer to `.main_container` in view
});
then you don't have to do $(".main_container").append(self._header.el);
if you must pass the parent into view as an options for some reason, then you should cache it in the view inside initialize
so that you can refer it elsewhere like.
this.parent = options.parent
side note:
As you can see, I've changed the order in which you had declared the view's properties - initialize
on top followed by template, event and render.
We initialize the view, we create the templating function, we declare the events to be delegated, and then we render the view.
The order in which you define properties doesn't matter internally, but when another developer looks at your code, it's much easier to digest. But it's a matter of opinion.
来源:https://stackoverflow.com/questions/33947966/backbone-click-event-not-firing-in-template-view