Trigger function on click if View has a certain cl

2019-02-18 07:33发布

问题:

I have a div generated by a backbone.js view. When the user clicks on this div, a class active is added to the div and the function addToSet is executed.

Problem: I want another function to be triggered when the View's div has the class active. However, my attempt shown below always cause addToSet function to run when its clicked.

Now, I remove 'click': 'addToSet' from the events function, leaving only 'click .active': 'removeFromSet'. Clicking on the div does not cause anything to happen! Is this because the event handler cannot select the div of the view itself, just the elements inside it?

Any idea how I can solve this problem? Thanks!

JS Code

SetView = Backbone.View.extend({
    tagName: 'div',
    className: 'modal_addit_set',

    template: _.template( $('#tpl_modal_addit_set').html() ),

    events: {
        'click': 'addToSet',
        'click .active': 'removeFromSet'
    },

    initialize: function(opts) {
        this.post_id = opts.post_id;
    },

    render: function() {
        $(this.el).html( this.template( this.model.toJSON() ) );
        if(this.model.get('already_added'))
            $(this.el).addClass('active');
        return this;
    },

    addToSet: function() {
        $.post('api/add_to_set', {
            post_id: this.post_id,
            set_id: this.model.get('id'),
            user_id: $('#user_id').val()
        });
    },

    removeFromSet: function() {
        $.post('api/remove_from_set', {
            post_id: this.post_id,
            set_id: this.model.get('id')
        });
    }
});

回答1:

These events:

events: {
    'click': 'addToSet',
    'click .active': 'removeFromSet'
}

don't work and you sort of know why. From the fine manual:

Events are written in the format {"event selector": "callback"}. The callback may be either the name of a method on the view, or a direct function body. Omitting the selector causes the event to be bound to the view's root element (this.el).

So your 'click': 'addToSet' binds addToSet to a click on the view's el itself but 'click .active': 'removeFromSet' binds removeFromSet to a .active element inside the view's el.

I think the easiest solution is to have a single event:

events: {
    'click': 'toggleInSet'
}

and then:

toggleInSet: function() {
    if(this.$el.hasClass('active')) {
        $.post('api/remove_from_set', {
            post_id: this.post_id,
            set_id: this.model.get('id')
        });
    }
    else {
        $.post('api/add_to_set', {
            post_id: this.post_id,
            set_id: this.model.get('id'),
            user_id: $('#user_id').val()
        });
    }
}

You could use an instance variable instead of a CSS class to control the branching in toggleInSet if that makes more sense.



回答2:

Have you tried to use a :not(.active) selector for one of your event delegates? This may help differentiate between the two scenarios.

Something like this:

events: {
   'click :not(.active)' : callback1
   'click .active' : callback2
}