Search code examples
javascriptbackbone.jsbackbone-views

How to swap a view's template and remove the old view


I have the following code:

switch (type) {
    case "countdown":
        this.render(_this.templates.countdown);
        break;
    case "timer":
        this.render(_this.templates.timer);
        if (App.Views.timer) App.Views.timer.remove();
        App.Views.timer = new Timer();
        break;
}

So, as I suppose when the template were rendered we're remove previous View, because the link on new DOM element changed. But I'm not sure what old view was really removed.

Because if I add console.log(App.Views.timer) after if (App.Views.timer) App.Views.timer.remove(); I get: child {cid: "view3", $el: jQuery.fn.init(1), el: div#timer.timer}. And it's look like nothing changed!

I have two questions.

  1. Is it correct way to remove view from memory?
  2. If I have a div which can change template, is it a correct way to create new View? Unfortunately, the solution to just hide the template does not suit my situation.

Solution

  • What does the view's remove function do?

    View's remove function just removes the element from the DOM while unbinding any DOM related events and Backbone specific events.

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

    The code for the remove function is:

    // Remove this view by taking the element out of the DOM, and removing any
    // applicable Backbone.Events listeners.
    remove: function() {
      this._removeElement();
      this.stopListening();
      return this;
    },
    

    About the view still in memory

    So it still lives in memory until you release any references left. Logging the view object to the console keeps it alive as it's a reference to it.

    Sharing a div for multiple views

    I wouldn't go your way on this. Instead of a switch case, you could use a Backbone Router with routes and then make yourself some kind of layout view.

    A super simple layout view could look like this:

    var LayoutView = Backbone.View.extend({
        initialize: function() {
            // caching the jQuery object on init
            this.$content = this.$('#content');
        },
        setContent: function(view) {
            var content = this.content;
            if (content) content.remove();
            content = this.content = view;
            this.$content.html(content.render().el);
        },
    });
    

    Used within a router:

    var Router = Backbone.Router.extend({
        routes: {
            'about': 'aboutRoute',
            'contact': 'contactRoute',
            // put the catch-all last
            '*home': 'homeRoute',
        },
        initialize: function() {
            // create the layout once here
            this.layout = new views.Application({
                el: 'body',
            });
        },
        homeRoute: function() {
            var view = new views.Home();
            this.layout.setContent(view);
        },
        aboutRoute: function() {
            var view = new views.About();
            this.layout.setContent(view);
        },
        contactRoute: function() {
            var view = new views.Contact();
            this.layout.setContent(view);
        }
    });
    

    I wrote a detailed answer on how to use a router with a simple layout view.