rpabon
rpabon

Reputation: 1201

Disable specific event in a Backbone.js view

I am working on a nested backbone view, in which if you click on, it will create a new instance of the same view. I want to disable only a specific event, not all of them; in this case, the click. I tried using undelegateEvents(), but this will disable all the functions. Any ideas on how can this be done?

Here is a piece of the code I am working on:

var View = Backbone.View.extend({
    events: {
        "mousedown": "start",
        "mouseup": "over"
    },

    start: function() {
        var model = this.model;

        var v = new View({
            model: model,
        });
        v.undelegateEvents(); //I just want to disable mousedown
        v.render();
    },

    over: function() {
        /*
        some code here
        */
    },

    render: function() {
        /*
        some code here
        */
    }
});

The idea is to ban clicking in the second instantiated view while keeping the other events. The first one will have all of its events.

Thanks

Upvotes: 4

Views: 4948

Answers (2)

Robb Hoff
Robb Hoff

Reputation: 1910

Here is a simple example that shows how to delegate or undelegate events within a Backbone view

Backbone.View.extend({

    el: $("#some_element"),

    // delete or attach these as necessary
    events: {
        mousedown: "mouse_down",    
        mousemove: "mouse_move",
        mouseup: "mouse_up",
    },  

    // see call below
    detach_event: function(e_name) {
        delete this.events[e_name]
        this.delegateEvents()
    },  

    initialize: function() {        
        this.detach_event("mousemove")      
    },  

    mouse_down: function(e) {       
        this.events.mousemove = "mouse_move"
        this.delegateEvents()       
    },

    mouse_move: function(e) {},

    mouse_up: function(e) {}

})

Upvotes: 1

mu is too short
mu is too short

Reputation: 434665

You can specify the events you want to use when you call delegateEvents:

delegateEvents delegateEvents([events])

Uses jQuery's delegate function to provide declarative callbacks for DOM events within a view. If an events hash is not passed directly, uses this.events as the source.

So you could do something like this:

var v = new View({
    model: model,
});
v.undelegateEvents();
var e = _.clone(v.events);
delete e.mousedown;
v.delegateEvents(e);
v.render();

You might want to push that logic into a method on View though:

detach_mousedown: function() {
    this.undelegateEvents();
    this.events = _.clone(this.events);
    delete this.events.mousedown;
    this.delegateEvents();
}

//...

v.detach_mousedown();

You need the this.events = _.clone(this.events) trickery to avoid accidentally altering the "class's" events (i.e. this.constructor.prototype.events) when you only want to change it for just one object. You could also have a flag for the View constructor that would do similar things inside its initialize:

initialize: function() {
    if(this.options.no_mousedown)
        this.detach_mousedown()
    //...
}

Another option would be to have a base view without the mousedown handler and then extend that to a view that does have the mousedown handler:

var B = Backbone.View.extend({
    events: {
        "mouseup": "over"
    },
    //...
});
var V = B.extend({
    events: {
        "mousedown": "start",
        "mouseup": "over"
    },
    start: function() { /* ... */ }
    //...
});

You'd have to duplicate the B.events inside V or mess around with a manual extend on the events as _.extend won't merge the properties, it just replaces things wholesale.

Upvotes: 7

Related Questions