1

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?

Luca Reghellin
  • 7,426
  • 12
  • 73
  • 118

2 Answers2

1

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
Vladu Ionut
  • 8,075
  • 1
  • 19
  • 30
  • Ok thenk you I'm gonna try. I already tried that solution but the browser just got stuck. Probably there was some other thing causing the issue. – Luca Reghellin Jul 08 '15 at 12:55
  • For some reason if I put `this.events = {...}` in initialize() or set_events(), it won't work. It will fail silently. Much like when jquery doesn't find the dom elements. But the functions are called on domready, so I cannot figure out what's the issue – Luca Reghellin Jul 09 '15 at 05:37
1

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.

Luca Reghellin
  • 7,426
  • 12
  • 73
  • 118
  • @VladuIonut's example just works, though, so it would be interesting find out why in my case I'm forced to regular events property placement. – Luca Reghellin Jul 10 '15 at 06:20