Question

Ok, so I'm having quite some difficulty getting event binding to work with Coffeescript and Backbone. I have a feeling it has to do with how I'm initializing everything; I feel like the event delegation isn't even being run.

Here is my view code:

$ ->
  class AppName.TitleView extends Backbone.View
    template: JST['templates/title']
    collection: new AppName.Members
    events:
      "keypress #search"      : "search",
    initialize: =>
      $('#search').keypress(@search) #doing it manually as a hack
    search: ->
      console.log('search handler call')
    render: =>
      $('#app').html(@template)
      @delegateEvents() #this doesn't seem to do anything, nor does @delegateEvents(@events)
      @

Which, when compiled, looks something like this:

(function() {
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
    __hasProp = Object.prototype.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };

  $(function() {
    AppName.TitleView = (function(_super) {

      __extends(TitleView, _super);

      function TitleView() {
        this.render = __bind(this.render, this);
        this.initialize = __bind(this.initialize, this);
        TitleView.__super__.constructor.apply(this, arguments);
      }

      TitleView.prototype.template = JST['templates/title'];

      TitleView.prototype.collection = new AppName.Members;

      TitleView.prototype.events = {
        "keypress #search": "search",
      };

      TitleView.prototype.initialize = function() {
        return $('#search').keypress(this.search);
      };


      TitleView.prototype.search = function() {

        console.log('search handler call'););
        });
      };

      TitleView.prototype.render = function() {
        $('#app').html(this.template);
        this.delegateEvents();
        return this;
      };

      return TitleView;

    })(Backbone.View);
  });

}).call(this);

AppName.TitleView is kicked off from my router (which is in turn kicked off by the main app.coffee) with:

$ ->
  class AppName.Router extends Backbone.Router
    routes:
      ".*": "main"

    main: ->
      @titleView ||= new AppName.TitleView el: $('#app')[0]
      @titleView.render()

But for the life of me, I cannot get the binding to #search from Backbone Events to bind. My hack (which is in the code) is just to bind via jQuery in the initialize function.

Any idea what's going on? I'm hoping this is a simple typo or bad initialization.

Was it helpful?

Solution

View events are bound to the view's el using the delegation form of jQuery's on. That means that everything you mention in the view's events object must be inside the view's el or the event handlers won't be triggered.

By default, a view's el is an empty <div> and the view will create that <div> when it needs to and bind the events to that <div>. You might notice that you're not using this.el or this.$el anywhere in your code; your events are being bound properly but they're being bound to anything that you put in the DOM and so it looks like the events aren't working.

Two immediate possibilities arise:

  1. Use #app as the view's el:

    class AppName.TitleView extends Backbone.View
      #...
      el: '#app'
      #...
      render: =>
        @$el.html(@template)
        @
    
  2. Do things the usual Backbone way and create an el just for your view:

    class AppName.TitleView extends Backbone.View
      #...
      render: =>
        @$el.html(@template)
        @
    
    v = new AppName.TitleView
    $('#app').append(v.render().el)
    

I'd recommend the latter as it is easier to manage and will help you avoid attaching multiple views to the same DOM element (and the zombies that tend to come from that).

Also, @template is almost always a function so you want to say:

$('#app').html(@template())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top