Luca Reghellin
Luca Reghellin

Reputation: 8113

Is Backbone's view 'events' property only for DOM events?

I've got this piece code in a view:

//dom events -----

,events:{
    'click #language-switcher input[type="radio"]': function(e){
        this.current_language = $(e.target).val();
    }
    ,'click .create-gcontainer-button': function(){
        this.collection.add(new Group());
    }
}

,set_events:function(){

    //model events -----

    this.listenTo(this.collection,'add',function(group){
        var group = new GroupView({ model: group });
        this.group_views[group.cid] = group;
        this.groups_container.append(group.el);
        EventTools.trigger("group_view:create",{ lang:this.current_language });
    });

    this.listenTo(this.collection,'destroy',function(model){
        console.log('removing model:', model);
    });

    //emitter events ---

    EventTools.on('group_view:clear',this.refresh_groups, this);

}//set_events

Note: set_events gets called on initialization. Well, I don't like defining events in 2 different places, but since the docs say that events defined from the 'events' prop are bound to the element (or children of it if a selector is passed), I guess I cannot use it for other types of events. Am I correct?

I also tried to define 'events' from inside my set_events function, but for some reason that leads to a memory leak or something similar (browser gets stuck).

So another more general question could be: on a Backbone view, is there a way to define all the events in one single place?

Upvotes: 1

Views: 683

Answers (2)

Luca Reghellin
Luca Reghellin

Reputation: 8113

As I commented above, for some strange reason, placing events inside initialize() or set_events() fails silently. I found out that doing one of the 2, backbone doesn't find the events. This backbone's view's function says undefined to console:

delegateEvents: function(events) {
  events || (events = _.result(this, 'events'));

  console.log(events); //outputs undefined

  if (!events) return this;
  this.undelegateEvents();
  for (var key in events) {
    var method = events[key];
    if (!_.isFunction(method)) method = this[method];
    if (!method) continue;
    var match = key.match(delegateEventSplitter);
    this.delegate(match[1], match[2], _.bind(method, this));
  }
  return this;
},

Though, if I place events like a regular view property, just as my code on the main question, it will correctly log the events.

Upvotes: 1

Vladu Ionut
Vladu Ionut

Reputation: 8193

Within a View, there are two types of events you can listen for: DOM events and events triggered using the Event API. It is important to understand the differences in how views bind to these events and the context in which their callbacks are invoked. OM events can be bound to using the View’s events property or using jQuery.on(). Within callbacks bound using the events property, this refers to the View object; whereas any callbacks bound directly using jQuery will have this set to the handling DOM element by jQuery. All DOM event callbacks are passed an event object by jQuery. See delegateEvents() in the Backbone documentation for additional details.

Event API events are bound as described in this section. If the event is bound using on() on the observed object, a context parameter can be passed as the third argument. If the event is bound using listenTo() then within the callback this refers to the listener. The arguments passed to Event API callbacks depends on the type of event. See the Catalog of Events in the Backbone documentation for details.

Yes you can define all the events in the view initialize method, see the below example

// Add your javascript here
var View = Backbone.View.extend({

  el: '#todo',
  // bind to DOM event using events property
  initialize: function() {
    // bind to DOM event using jQuery
    this.events = {
      'click [type="checkbox"]': 'clicked'
    };
    this.$el.click(this.jqueryClicked);
    // bind to API event
    this.on('apiEvent', this.callback);
  },

  // 'this' is view
  clicked: function(event) {
    console.log("events handler for " + this.el.outerHTML);
    this.trigger('apiEvent', event.type);
  },

  // 'this' is handling DOM element
  jqueryClicked: function(event) {
    console.log("jQuery handler for " + this.outerHTML);
  },

  callback: function(eventType) {
    console.log("event type was " + eventType);
  }

});

you can see the demo here

for your code

set_events:function(){

    //dom events -----
    this.events={
        'click #language-switcher input[type="radio"]': function(e){
            this.current_language = $(e.target).val();
        }
        ,'click .create-gcontainer-button': function(){
            this.collection.add(new Group());
        }
    };

    //model events -----

    this.listenTo(this.collection,'add',function(group){
        var group = new GroupView({ model: group });
        this.group_views[group.cid] = group;
        this.groups_container.append(group.el);
        EventTools.trigger("group_view:create",{ lang:this.current_language });
    });

    this.listenTo(this.collection,'destroy',function(model){
        console.log('removing model:', model);
    });

    //emitter events ---

    EventTools.on('group_view:clear',this.refresh_groups, this);

}//set_events

Upvotes: 1

Related Questions