Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js: nesting views through templating

Is it technically possible to nest views, using templating, something like that:

<%= new PhotoCollectionView({model:new PhotoCollection(model.similarPhotos)}).render().el) %>

I can put all the stuff in the render method as well, but templating gives much more room for flexibility and layout.

I tried the aforementioned variant, but all I get as a result on the screen is [HTMLDivElement].

If I try to extract just the HTML out ouf it, using jQuery's HTML, I get it rendered, but it turns out that the DOM nodes that get printed out are different from the ones that the views hold a reference to, because no interaction whatsoever with those DOM nodes is possible using the view instance. For instance if within the view I say $(this.el).hide(), nothing will happen.

What is the proper way, if any?

like image 228
user802232 Avatar asked Aug 18 '11 19:08

user802232


2 Answers

I typically render the parent view first. I then use the this.$('selector') method to find a child element that I can use as the el of the child view.

Here is a full example:

var ChildView = Backbone.View.extend({
  //..
})

var ParentView = Backbone.View.extend({
  template: _.template($('#parent-template').html()),
  initialize: function() {
    _.bindAll(this, 'render');
  }
  render: function() {
    var child_view = new ChildView({ el: this.$('#child-el') }); //This refers to ParentView. 
    return this;
  }
});

var v = new ParentView();
v.render(); 
like image 51
Skylar Anderson Avatar answered Oct 18 '22 11:10

Skylar Anderson


The accepted answer has a major flaw, which is the fact that the ChildView is going to be re-initialised everytime it's rendered. This means you will lose state and potentially have to re-initialised complicated views on each render.

I wrote a blog about this here: http://codehustler.org/blog/rendering-nested-views-backbone-js/

To summarise though, I would suggest using something like this:

var BaseView = Backbone.View.extend({

    // Other code here...

    renderNested: function( view, selector ) {
        var $element = ( selector instanceof $ ) ? selector : this.$el.find( selector );
        view.setElement( $element ).render();
    }
});

var CustomView = BaseView.extend({

    // Other code here...

    render: function() {
        this.$el.html( this.template() );
        this.renderNested( this.nestedView, ".selector" );
        return this;
    }
});

You do not need to extend the Backbone view if you don't want to, the renderNested method could be put anywhere you like.

With the code above, you can now initialise the ChildView in the initialisation method and then simply render it when render() is called.

like image 41
Alessandro Giannone Avatar answered Oct 18 '22 11:10

Alessandro Giannone