Backbone has no native abstraction layer for working with nested views, and even though this is a very common problem and there are a lot of great and well-maintained libraries, none of them ticked all our boxes:

In order to maintain a clear separation of concerns Assembler uses templates in the dumbest way possible - They do not know about child views so no controller/view responsibilities like view hierarchies, data loading, contexts or filters leak into your templates. Instead layouts are managed directly in the view, which allows you to add/remove/swap/position/observe child views programmatically as well as giving you the flexibility to use any template engine of your choice (or even raw string concatenation).

Assembler has been designed from the ground up to render nested views server-side and re-attach them client side. This allows you to build one page applications, which serve fully rendered markup without having to duplicate your presentation logic.

Destination strings are composed of an insert method and can optionally be followed by a CSS selector that identifies the target element. If no target selector is provided the view's root element itself becomes the target. (Useful for creating flat lists)

The following insert methods are supported:

inner - Replaces the contents of the target element with the child view

outer - Replaces the target element with the child view

prepend - Inserts the child view at the beginning of the target element

The inverse of .render() - Call this to re-attach your complete layout to all DOM elements when you can guarantee that all your model/collection data fully reflects what was used to render the markup server side.

In order to help build self-contained modules Assembler assumes that each view knows what data is required to render itself and when that data is available. This is usually the model and/or collection used by the view but could also include an asynchronously fetched template or additional data sources like i18n dictionaries.

Call this method to check if the view is ready to be rendered. Automatically delegates to model.fetch and collection.fetch passing on any options set.

Calling ready on a layout propagates down to all its child views chaining together all their ready promises. This makes it easy to work with deeply nested layouts, which can only be rendered once all their child views (and all of their child view's child views and so on) are ready.

Similar to addView except that Assembler waits until the view to be inserted is ready to be rendered (all model/collection data has been fetched) before removing the current child view from, and inserting the new child view to, the layout.

List views are tightly coupled to their collection and will automatically create and add view instances of type itemView for every model in collection into the layout at itemDestination:

var linksView =newAssembler.ListView({

tagName:'ul',

itemView: Assembler.View.extend({tagName:'li'}),

collection: links,

collectionEvents:{

'add remove reset sort':'render'

}

});

A list's item views are fully managed by its collection so don't add/remove them manually using any layout methods. Instead add/remove/reset/sort the collection directly. Feel free to add unrelated child views though as you would in any other layout.

Furthermore, since list views are essentially layout views with added sugar for collections, they can also be used to create composite views (templated lists) by setting a template and overriding the default itemDestination like so:

var linksView =newAssembler.ListView({

template:'<ul></ul> <aside></aside>',

itemView: Assembler.View.extend({tagName:'li'}),

itemDestination:'append ul',

collection: links,

collectionEvents:{

'add remove reset sort':'render'

},

views:{

"inner aside": relatedView

}

});

When working with large collections it is useful to debounce calls to render in your event listeners to avoid having to re-render the whole list for each add and remove event emitted. This is because collections fire events for each model individually even if added/removed in one go (e.g. after a fetch/reset/sort). The following technique can be used to ensure the list is only being rendered once after the last model has been added: