Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
378 views
in Technique[技术] by (71.8m points)

backbone.js - Backbone click event not firing in template View

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...