-1

I am trying to make my very first search app.

After the app is built, every DOM is rendering as I expect and events work as well. When I dig deeper into it, I find a strange behavior, and after I did some search, I found it is because of zombie view events delegate issue.

Here is some part of my code:

var searchList = Backbone.View.extend({
    events:{
        'click #submit':function() {
            this.render()
        }
    },
    render() {
        this.showList = new ShowList({el:$('.ADoM')});
    }
});

When #submit is clicked, a new instance of ShowList will be created and '.ADoM' DOM will be rendering.

showList.js

var showList = Backbone.View.extend({

    events: {
        "click .testing": function(e) {
            console.log(e.currentTarget);
        },
    },
    initialize() {
        this.$el.html(SearchListTemplate());
    }
});

The '.testing' button event is bound with it.

So as what 'zombie' does, after multiple clicks on submit, then clicking the '.testing' button, console.log() will output multiple time.

I have followed the article here and tried to understand and fix my issue, and also tried to add this.remove() in showList.js as someone mentioned, but unfortunately it may because I was not able to place them in the proper place in my code, the issue is still unsolved.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
MMzztx
  • 243
  • 5
  • 15
  • Be cautious with anything related to Backbone written before 2013 as it changed a lot and old articles and tutorials are often showing bad practices. – Emile Bergeron Dec 22 '17 at 21:02

1 Answers1

1

That has nothing to do with ES6, this is basic JavaScript and DOM manipulation.

Do not share the same element in the page

You're creating new ShowList instances which are bound to the same element in the page. In Backbone, that's bad practice.

Each Backbone View instance has its own root element on which events are bound. When multiple views share that same element, events are triggered on each instance, and you can't call remove on the view since it will remove the DOM element from the page completely.

You should dump the child view root element within the element you wish to reuse.

this.$('.ADoM').html(this.showList.render().el);

Reusing the view

The render function should be idempotent.

var searchList = Backbone.View.extend({
    events: {
        // you can use a string to an existing view method
        'click #submit': 'render'
    },
    initialize() {
        // instanciate the view once
        this.showList = new ShowList();
    },
    // This implementation always has the same result
    render() {
        this.$('.ADoM').html(this.showList.render().el);
        // Backbone concention is to return 'this' in the render function.
        return this;
    }
});

Your other view could be simplified as well to reflect the changes from the parent view.

var showList = Backbone.View.extend({
    events: {
        "click .testing": 'onTestingClick',
    },
    // Don't render in the initialize, do it in the render function
    render() {
        this.$el.html(SearchListTemplate());
    },
    onTestingClick(e) {
        console.log(e.currentTarget);
    }
});

This is a super basic example on reusing a view instead of always creating a new one.

A little cleanup is necessary

When done with a view, you should call remove on it:

Removes a view and its el from the DOM, and calls stopListening to remove any bound events that the view has listenTo'd.

For this to work, when registering callbacks on model or collection events, use listenTo over on or bind to avoid other memory leaks (or zombie views).

A good pattern for view having multiple child views is to keep a reference of each child views and call remove on each of them when the parent gets removed.

See how to avoid memory leaks when rendering list views. When dealing with a lot of views (big list or tree of views), there are ways to efficiently render with Backbone which involves DocumentFragment batching and deferring.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • Thanks a lot for your nice and detail explanation! That is a great help to new backbone learner! Appreciate! – MMzztx Dec 23 '17 at 16:21