Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js - Remove all sub views

Tags:

backbone.js

I have a top level PageView that will re-render itself whenever the route changes. I have many nested sub-views embedded into this PageView. If I was to re-render PageView, do I need to remove/unbind all the nested sub-views along with the PageView or do I only need to remove/unbind the PageView? If I need to remove/unbind all the sub-views, what is the best way to go about doing this?

like image 918
teggy Avatar asked Mar 01 '12 19:03

teggy


People also ask

How do I delete a backbone view?

remove() The Backbone. js remove method is used to remove the view from the DOM. It calls stopListening to remove any bound events that the view has listenTo.

Why use Backbone js?

BackboneJS allows developing of applications and the frontend in a much easier way by using JavaScript functions. BackboneJS provides various building blocks such as models, views, events, routers and collections for assembling the client side web applications.

What is Backbone in programming?

Backbone. js is a model view controller (MVC) Web application framework that provides structure to JavaScript-heavy applications. This is done by supplying models with custom events and key-value binding, views using declarative event handling and collections with a rich application programming interface (API).


3 Answers

Yes, you need to properly remove and unbind them:

http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/

The easy way to do this is to store an array of your sub-views in the parent view. Then in a close method on the parent view, loop through the array and call a close method on the child views:

ParentView = Backbone.View.extend({
  initialize: function(){
    this.childViews = [];
  },

  render: {
    for (var i = 0; i < 10; i++){
      var childView = new ChildView();
      // do stuff with the child view
      this.childViews.push(childView);
    }
  },

  close: function(){
    this.remove();
    this.unbind();
    // handle other unbinding needs, here
    _.each(this.childViews, function(childView){
      if (childView.close){
        childView.close();
      }
    })
  }
});

Be sure to call the close method on the parent view when you are ready for it to be removed / replaced. This will ensure all of the children are cleaned up properly (assuming all of them have their own close method).

like image 129
Derick Bailey Avatar answered Oct 14 '22 21:10

Derick Bailey


A simple and modular class you might find useful.

ContainerView = Backbone.View.extend({
  initialize: function() {
    this.children = [];
  },
  remove: function() {
    Backbone.View.prototype.remove.apply(this, arguments);
    this.removeAllChildren();
  },
  removeAllChildren: function() {
    _.each(this.children, function(view) { view.remove(); });
    this.children = [];
  },
  appendAllChildren: function() {
    _.each(this.children, function(view) { this.$el.append(view.render().$el); }, this);
  }
});

usage:

MyView = ContainerView.extend({
  render: function() {
    this.removeAllChildren();
    this.$el.empty();

    // For each child view...
    // this.children.push(new SomeControl(...));

    this.appendAllChildren();
    return this;
  }
});
like image 3
Aaron Averill Avatar answered Oct 14 '22 20:10

Aaron Averill


Instead of keeping an array of children view, could iterate through all the properties of your view and see which ones are an instance of Backbone.View; you will need to make sure to set a property for each child view in your parent view.

In the example below, the child views are set to properties of the parent view. I'm not sure what the performance hit will be looping through all the properties, however, it may be easier than keeping track of a separate data structure for the child views.

Example:

var ContextView = Backbone.View.extend({
    initialize: function() {
      // views render themselves via their initialize methods
      this.titlebar = new TitlebarView({el: $("#titlebar")});       
      this.toolbar = new ToolbarView({el: $("#toolbar")});
      this.content = new ContentView({el: $("#content")});
    },
    removeChildViews: function() {      
        for(var prop in this){
            if (this[prop] instanceof Backbone.View) {
                console.log("This is a view: "+ prop + ' in ' + this[prop]);    
            }
        }
    }, 
    render: function() {
        this.$el.html(this.el);
    }
  });
like image 2
Zengineer Avatar answered Oct 14 '22 20:10

Zengineer