Part 3: Handling Sub-Views with Layouts

Posted by Dave Bouwman on February 25, 2013

“Marionette Maps” is an on-going series on building a loosely coupled, configuration driven map viewer using Marionette.js. Read Part 1, Part 2

 

The next thing we will implement is a layer list. Now, I know some of you don’t much care of layer list controls, and I tend to agree, but they just happen to be a good way to review Layouts, so bear with me. 

 The Layer List

So, let’s look at what we are trying to create – here’s a screen cap of the finished layer list.

Layer List Image

Pretty simple stuff right? 

We could just use static mark up, drop in some data-* attributes, use jquery to handle some click events, locate the layer in the map, and toggle it’s visibility, right?

That works, but is a recipe for spaghetti code and maintenance nightmares. A much better options is to structure this into a configurable, modular, loosely coupled component. This means that our Layer List should have no direct knowledge of the Map and vice versa. We will communicate between the two with Events.

Looking at the design, we have a header area, with a title, an icon to close out the view, and two lists – one for operational layers, and the other for base maps. The first thing we have to think about is: Where will we get these lists from? One option would be to query the map component, but since we are sending configuration json into the app, lets use that.

Map Layer Configuration

To keep things organized, I’ve added mapConfig into our options hash, and added base maps and operationalLayers below that, as seen in the following gist.

With this in place, we can create a module & controller just like we did last time, and in the initialize() of the controller, we pull the two arrays of layers from the mapConfig and start using them.

Since these arrays don’t change at run-time, we can do all the work in initialize(). The steps are as follows:

  1. Convert the arrays into Backbone collections
  2. Create the CollectionViews, and pass in the Collections.
  3. Create the LayoutView
  4. Call render() on the LayoutView by passing it into the module’s region.show() method (more below on this)
  5. Call show() on the regions in the layout, passing in the collection views created in #2
  6. Register Event Handlers to show/hide the panel

Here’s the initialize method:

More on Layouts…

A Marionette.Layout is a view that is specifically designed to have sub-views. In our case, the sub-views will be the two lists. Layouts handle this by having a set of Regions. Regions are defined using a selector, and are basically a container into which views can be rendered. Recall that we don’t simply inject views into the DOM directly, instead we use Regions, as they will handle all the event clean up for us.

Let’s look at the markup…

As usual, the markup in the page itself is minimal – just a div with and id. The layer-list-template is the template for the Layout. As you can see, it has div’s with id’s basemaps-list and layers-list respectively. These are the Regions, which will be populated by CollectionViews rendering ItemViews which use the basemap-item-template and layer-item-template. 

Here is a snipped showing the Layout

 

If you look at the initialize method snipped above, you will see that we have to render these things in order. Before we can call .show() on the Layout’s regions, their DOM nodes need to be in the DOM. Adding complexity here is that our Layout is itself being rendered into a Region ( that the this.region.show(this.layout) bit).

Since I covered ItemViews and Collection views in Part 2, I’ll let you look at the source for those details.

Once again, I created a jsfiddle while I was wrapping my head around using a Layout that itself was rendered into a Region. 

Code 

Code for this post is tagged v0.0.3 on github

Latest version of the app can be seen at http://dbouwman.github.com/geomacmapper