2

I am learning backbone.js and am quite new. I have a view that acts as a button:

simpleButton = Backbone.View.extend({
     template: "<button class='${classes}'>${text}</button>",

     el: $("body"),

     events: {
         "click": "onClick",
         "focus": "onFocus",
         "blur": "onBlur"
     },

     initialize: function (args) {

         _.bindAll(this, 'render');
         this.rendered = false;
         this.text = args.text || 'button';
         this.classes = args.classes || [];
         this.classes.push('ui-button');
         //console.debug("Wh.views.simpleButton.initialize classes ",this.classes);
         if (args.autoRender === true) this.render();

     },

     render: function () {
         //console.debug("Wh.views.simpleButton.render classes ",this.classes);
         if (this.rendered === false) {
             $.tmpl(
                 this.template, {
                     classes: this.classes.join(' '),
                     text: this.text
                 }
             ).appendTo(this.el);
             this.rendered = true;
         }

     },

     //event handlers
     onClick: function (ev) {
         console.debug(this);
         alert("click on ", ev, this);
     },

     onFocus: function (ev) {
         ////console.debug(ev);
     },

     onBlur: function (ev) {

     }

 });

My problem is that if I create two buttons, and click just one of them, I get the alert box two times, and the debug showing me "this" shows the first button first, and the second button next.

Am I missing something?

Nikhil Agrawal
  • 26,128
  • 21
  • 90
  • 126
Vlad Nicula
  • 3,577
  • 6
  • 32
  • 50
  • see : http://stackoverflow.com/questions/6402915/backbone-js-events-in-my-views-being-triggering-multiple-times – charlysisto Aug 27 '11 at 06:56

4 Answers4

4

The events you define are bound to the "el" property of your view. In your case it is "body" so when you fire up click with 2 simpleButton views instantiated, you have 2 of them listening for the same event.

Each view you instantiate should represent one and only one DOM element defined by the el property. So if you want to create a button view (not sure this is 'best practice' in a real program) you could have :

SimpleButton =  Backbone.View.extend({
        template : "<button class='${classes}'>${text}</button>",

        tagName : "div", // defines the html tag that will wrap your template
        className: ".buttonbox", 
        ...
});

mybtn = new SimpleButton();
mybtn.render().appendTo('body')

That way your click event will only concern the one div.buttonbox inside of which your button lives.

Notice : Backbone idea of the render function is creating an html string you'll use afterwards to append prepend or whatever in the DOM. That way if you create many you can do it so you only refresh the DOM once (refreshing the DOM is expensive)...

charlysisto
  • 3,700
  • 17
  • 30
  • Thanks for clarifying that. It's good now. I decided to add a .inner class to the template of my buttons, and now I am listening to click .inner and it work, it doesn't fire two time! – Vlad Nicula Sep 05 '11 at 11:45
3

Use this in your View .it will unbind the click events

initialize : function() {
    $(this.el).unbind("click");
}
John Conde
  • 217,595
  • 99
  • 455
  • 496
suresh
  • 31
  • 1
1

Just a thought that creating a Backbone.View for each and every button in your app could be a performance overkill and you can't leverage the "delegate" feature in jQuery. I'd instead create a Backbone.View for the parent element of those buttons instead.

Of course, if you have a few special buttons with complicated logic then they probably do deserve their own View classes. :)

anh_ng8
  • 1,100
  • 10
  • 16
  • I have a form with alot of inputs and had to create a view (and model) for each since each is a model that corresponds to an api call. Do you think that's overkill? – gerl Jan 28 '14 at 17:06
  • @gerl: It is hard to quantify "a lot of inputs". However, let's say you have 10-20 inputs in a form, and you have to create each view for each of them then yes, it sounds like an overkill. What I would do is refactor the "model" to include more information to populate more inputs so you would be able to cut down on the number of views/models for that form. – anh_ng8 Feb 24 '14 at 06:22
0

Give your buttons unique ids, for example <button id="button1"> and <button id="button2">, then in your events hash, you need to specify the click event and the id of the button you want to handle that event for, e.g:

events : {
        "click #button1" : "onClick",
        "click #button2" : "doSomethingElse"
    }

Now this will call onClick() only when you click on the button with id=button1 and call doSomethingElse() when you click on the button with id=button2

cjroebuck
  • 2,273
  • 4
  • 30
  • 46
  • I wanted to be able to make as many buttons as I want, so the #id solution is not the one for me. However you are right, this #id thing work. Thank you. – Vlad Nicula Sep 05 '11 at 11:44
  • 1
    use a class then instead, and apply it to all your button's ` – cjroebuck Sep 05 '11 at 12:50