简体   繁体   中英

Backbone - bind and unbind events on current view

I'm trying to understand whether is necessary to unbind an event that is binded on the current instance of a view . For instance when I do:

$(this.el).on('click', callback);

is it necessary to unbind the events (eg using off() or $(this).unbind('click') inside the callback function) or maybe the view will destroy the event and will give it to garbage collector?

You should setup all of your events via the View's events hash and only unbind them when removing a view via .remove() .

Backbone Views use Event Delegation for the DOM Event handlers, so you can set up events for View HTML that doesn't exist yet, and, once the HTML is generated, the event handlers will catch the events as expected. All events handlers are attached to the views root element and watch for specific events that occur within that element or it's children.

Events will be unbound when you remove the view via Backbone.View.remove()

view.remove();

If you need to unbind events while the view is displayed (not common), you can specifically unbind that event via jQuery's .off() , but, you shouldn't have to (or want to) manage binding/unbinding your events.

The problem with manually unbinding events is that you may/probably will quickly find yourself conditionally unbinding and binding these event handlers according to user input. You'll go down the path of "unbind an event here, rebind it here, but unbind when this condition is true or this one is false"... it gets confusing, fragile and unmaintainable very quickly.

Instead, you should keep your DOM Bindings bound all of the time and have their execution dependent on the State of the view... sometimes the event handlers may do nothing, but that's fine. With this style of writing views, you're only concern with DOM events is that you remove your views properly. Inside the the view's state, you can consolidate the business logic behind when the views should respond to certain events.

What does State look like, in code?

initialize: function {
    this.state = new Backbone.Model({ /* initial state */ });
}

Boom. It's that easy. State is just an object (or backbone model) where you can store data about the current state of the view. It's like the Views little junk drawer of useful data.

Should the save button be disabled?

this.state.set('save_button_disabled', true);
this.state.set('save_button_disabled', false);

Is the form validated? Errors?

this.state.set('form_valid', false);
this.state.set('form_errors', errorsArray);

Then bind some handlers to it, and when user does something, update the state and let the handlers handle it. Recording and responding to state changes will force you to write your views with lots of small functions that are easy to test, easy to name and easy to maintain. Having a dedicated object to store state is a great way to organize and consolidate the logic & conditions within the view.

this.listenTo(this.state, {
    'change:save_button_disabled': this.toggleSaveButton,
    'change:form_valid': this.onFormValidationChange
});

You can also tap into state within your views event handlers:

events: {
    'click button.save': 'onSaveClicked'
},
onSaveClicked: function() {
    if ( this.state.get('form_valid') ) {
        /* do save logic */
    }
}

As your application grows, you might also want to look into separating state into View State, Environment State (test, prod, dev, versions etc), User State (logged in/out, admin, permissions, users birthday? etc) and others. View State is usually the first step.

Your view should essentially be a bunch of small concise functions that respond to DOM, State and Model/Collection events. It should not contain the complex logic that evaluates, responds to and interprets user input and model data.. that complex stuff should exist in the Collections, Models and State. The view is simply a representation of those items and interface for the user to interact with them, just like the front-end of a web-app is an interface for the user to interact with a database.

View Code:

var MyView = Backbone.View.extend({
    events: {
        "click": "onClick"
    },
    "onClick": function() {
        if ( this.state.get('clickable') ) {
             /* do callback */
        }
    },
    initialize: function(options) {
        this.options = options;
        this.state = new Backbone.Model({ clickable: true });
    },
    getTemplate: function() { /*...*/ },
    render: function() {
        var template = this.getTemplate(),
            data = {
                options: this.options,
                data: this.model.toJSON(),
                state: this.state.toJSON()
            };

        return this.$el.html(template(data));
    }
});

Template Code:

{{#if state.logged_in}}
    <p {{#if options.large}}class="font-big"{{/if}}>
        Welcome back, {{data.userName}}.
    </p>
{{else}}
    <p>Hello! {{#sign_up_link}}</p>
{{/if}}

Here's a simple example: http://jsfiddle.net/CoryDanielson/o505ny1j/

More on state and this way of developing views

In a perfect world, a View is a merely a interactive representation of data and the many different states of an application. Views are state machines. The view is also a small buffer between the user and data. It should relay the user's intentions to models/collections as well as the model/collection responses back to the user.

More about this:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM