A Layout is used to define structure; its intention is to create a skeleton where other views will be placed. A common web application layout is composed of a header, a sidebar, footer, and a common area, for example. With layouts we can define regions, in a declarative way, where these elements will be placed. After the layout is rendered, we can show the views we want on those views.
In the following figure, we can see a layout; each of these elements is a region, so other views should be created to fill the regions—for example, a HeaderView class for the header region:
An implementation of this example could be something like this:
var AppLayout = new Layout({ template: $('#app-layout').html(), regions: { header: 'header', sicebar: '#sidebar', footer: 'footer', main: '#main' } }); Var layout = new AppLayout({ el: 'body' }); var header = new HeaderView(); layout.render(); layout.getRegion('header').show(header);
See how regions are declared: a pair of names and a selector. The layout will expose the regions through the getRegion()
method, which receives the name of the region and returns an instance of the Region
class that can be used as seen in the previous section.
Also note that the layout needs to define a template
property; it should follow the same rules used in the ModelView
implementation. That template will define the HTML where regions will be pointed.
The following code shows how to create a Layout view:
class Layout extends ModelView { render() { // Clean up any rendered DOM this.closeRegions(); // Render the layout template var result = ModelView.prototype.render.call(this); // Creand and expose the configurated regions this.configureRegions(); return result; } configureRegions() { var regionDefinitions = this.regions || {}; if (!this._regions) { this._regions = {}; } // Create the configurated regions and save a reference // in the this._regions attribute _.each(regionDefinitions, (selector, name) => { let $el = this.$(selector); this._regions[name] = new Region({el: $el}); }); } // Get a Region instance for a named region getRegion(regionName) { // Ensure that regions is a valid object var regions = this._regions || {}; return regions[regionName]; } // Close the layout and all the regions on it remove(options) { ModelView.prototype.remove.call(this, options); this.closeRegions(); } closeRegions() { var regions = this._regions || {}; // Close each active region _.each(regions, region => { if (region && region.remove) region.remove(); }); } }
The layout extends directly from ModelView
so the render()
method acts like in ModelView
, but extends its behavior creating the necessary regions after rendering. The configurateRegions()
method creates a region for every region declared on the regions
property. Associations between region names and Region
instances are stored in the _regions
property, to be used on future references.
When a layout is removed, it should close any region opened, so that all resources are released cleanly. That's the job of the closeRegions()
method; it iterates over all regions created with configurateRegions()
and calls the remove()
method for every region.
As the regions are stored in a private property called _regions
, a method for accessing the regions is required; the getRegion()
method returns the region instance associated with the name of the region.
18.119.138.202