Search code examples
jquery-mobilebackbone.jsjquery-events

Adding events to button doesn't work with backbone


I read over 20 different articles and forum topics about that, tried different solutions but I didn't cope with it. The following code doesn't work. I need someone's help...

LoginView.js

var LoginView = Backbone.View.extend({   
    //el: $('#page-login'),
    initialize: function() {
        _.bindAll(this, 'gotoLogin', 'render');
        //this.render();
    },

    events: {
        'click #button-login': 'gotoLogin'
    },

    gotoLogin : function(e){
        e.preventDefault(); 
        $('#signup-or-login').hide();           
        $('#login').show();
        return true;
    }       
});

login.html

<div data-role="page" id="page-login">

<!-- SignUp or Login section-->
<div id="signup-or-login" data-theme="a">
    <a data-role="button" data-theme="b" id="button-signup"> Sign Up </a>
    <a data-role="button" data-theme="x" id="button-login"> Login </a>      
</div>

<!-- Login section--> 
<div id="login" data-theme="a">
    <button data-theme="b"> Login </button>
    <button data-theme="x"> Cancel </button>
</div>

</div>

The page is created in method of Backbone.Router extended class.

loadPage('login.html', new LoginView());

Solution

  • From what I understand, $.mobile.loadPage() grabs the desired html and attaches it to the DOM.

    Currently, you're trying to set el after the View has been instantiated.

    However, notice that Backbone.View attaches el and $el when it's instantiated:

    var View = Backbone.View = function(options) {
      ...
      this._ensureElement();
      this.initialize.apply(this, arguments);
      this.delegateEvents();
    };
    

    Also notice that View.setElement() sets $el by passing a selector or a jQuery objected to View.el:

    setElement: function(element, delegate) {
      if (this.$el) this.undelegateEvents();
      this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
      this.el = this.$el[0];
      if (delegate !== false) this.delegateEvents();
      return this;
    }
    

    Bottom line:

    You need to set el (in your case with the provided jQuery object) while instantiating it:

    // Where `view` is a reference to the constructor, not an instantiated object
    var loadPage = function(url, view) {
    
      $.mobile.loadPage(url, true).done(function (absUrul, options, page) {
        var v,
            pageId = page.attr('id');
    
        v = new view({
          el: page
        });
    
        ...
      }
    
    }
    

    You now call loadPage() like so:

    loadPage('login.html', LoginView);
    

    This gives Backbone.View the $el which to delegate your events.