24

I am creating a single page application, and I am quite new to backbone. I have a problem with creating multiple views which uses the same wrapper-div.

My setup:

I have added a close function to all views:

Backbone.View.prototype.close = function(){
    this.remove();
    this.off();
    if (this.onClose){
        this.onClose();
    } 
}

I have a wrapper-div where I want to render views, remove them and render new ones. So my SetupView looks like this:

app.SetupView = Backbone.View.extend({
    el: '#my_view_wrapper',
    ...
});

From the function where I swap views I close the current (open) view like this:

var v = this.model.get('view');
v.close();

Question

My problem is that I have multiple view's using the same wrapper-div. But when I close a view, this wrapper-div seems to be removed, and the next view I try to create can't find this div.

I guess there is an easy solution? I want to reuse the same wrapper, and only remove the view inside it, not the wrapper itself.

swenedo
  • 3,074
  • 8
  • 30
  • 49
  • `remove` removes the element from the DOM. But I think I misunderstood `el`. I thought it just was the place the new element got injected, but have now learned that it becomes a part of the new element, and therefor it is removed when i call `remove`. – swenedo Dec 30 '12 at 21:51
  • 3
    Right. You're generally better off letting each view manage its own `el`: the view should create its `el`, do things to it, and remove it when the view is removed. The caller puts the view's `el` inside a container that the caller controls. Not re-using DOM elements for multiple views helps you avoid a lot of problems. – mu is too short Dec 30 '12 at 22:00
  • 1
    @muistooshort - good advice. never thought about this - makes perfect sense. thank you. – cheshireoctopus Feb 06 '15 at 21:50
  • 1
    @cheshireoctopus Yeah, it solves so many problems and simplifies everything, I don't know why people do it any other way. – mu is too short Feb 06 '15 at 23:00

2 Answers2

25

Just as an addition (for later reference) : another option is to overwrite the subviews remove so that it just empties $el instead of removing it. Eg.

remove: function() {
      this.$el.empty().off(); /* off to unbind the events */
      this.stopListening();
      return this;
}

Personally I prefer this, as it removes the need to insert wrapper elements that have no real use.

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
Marcus
  • 5,083
  • 3
  • 32
  • 39
  • 1
    I agree. this method should be built into Backbone, switching between `empty` and `remove` based on whether an `el` is declared or not. – Tri Nguyen Mar 19 '14 at 15:10
  • 6
    I would also add `this.$el.empty().off()` as well to make sure all events are turned off. – Tri Nguyen Mar 19 '14 at 15:55
  • 1
    For reference, Backbone's implementation is [here](http://backbonejs.org/docs/backbone.html#section-158). – nucleartide Oct 15 '15 at 21:51
17

In your scenario don't use an existing DOM element as your "el" value. Backbone will create the element for you. When you instantiate your view you can do the following to attach it to your existing wrapping element.

$(viewName.render().el).appendTo('#my_view_wrapper');
mu is too short
  • 426,620
  • 70
  • 833
  • 800
Matt
  • 256
  • 2
  • 4