简体   繁体   中英

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?

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(); 

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.

Check out the Backbone.Subviews mixin. It is a minimalist mixin built for managing nested views and does not re-initialize the child views every time the parent is rendered.

I don't know about within a template itself, but I've done it with tables and lists before. In the outer template, just have the stub:

<script type="text/template" id="table-template">
    <table>
        <thead>
            <th>Column 1</th>
        </thead>
        <tbody>
        </tbody>
    </table>
</script>

and for the individual items: <%= field1 %>

then in your render method, just render the individual items and append them to the tbody element...

The decision to initialize a new object every time you render seems to me very inefficient. Particularly this:

render: function() {
    var child_view = new ChildView({ el: this.$('#child-el') }); //This refers to ParentView. 
    return this;
  }

Ideally the Rendering of the parent should be something like

render: function() {
   this.$el.html(this.template());
   this.childView1.render();
   this.childView2.render();
}

And the children creation should happen only when initializing the parent:

initialize: function() {
       this.childView1 = new ChildView1(selector1);
       this.childView2 = new ChildView2(selector2);
} 

the problem is that we do not have selector1 and selector2 before rendering the parent template. This is where I am stuck at right now :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM