Structuring Meteor-resque Handlebars-Templates

I don’t like the whole idea of HTML-templates very much. But I guess I have to take that route, at least at the moment. Many modern web-app frameworks and libraries use template engines to structure their views. So does Meteor and since I have chosen it for my current project, I’m into it, if I want to or not. And I must say it isn’t only bad.

After my smooth start with Meteor I had a hard time learning, how to use templates right. I’m still a little doubtful, if I really got it.  I couldn’t find a complete guide covering all of my use cases. So I decided to write my own guide. And had also the goal in mind, that that would lead to a better understanding. This often happens, when I have to linearize my thoughts.

Meteor basically uses Handlebars, and just wraps some sugar around it. This has positive effects as well as negative ones. On the pro-side the Meteor-guys made it easy and natural to write templates and the associated helpers. I looked at the pure Handelbars code and had immediately question marks in my eyes. ‘How do I include this stuff in a meaningful way into my app?’, felt to be the hardest thing to grasp. On the con-side the handlebars documentation can’t be applied straight away and requires some thinking-around-corners when you get stuck somewhere.

The Basics

The basic stuff just works. So I don’t mind loosing many words and let the code speak for itself in the following gists. They cover the foundations from different angles. At first a really bare example. Each mustache-expression ({{some_value}}) lets Meteor call the corresponding helper function and replace the mustache with the returned value in the outcome.

The next gist arrives at the same outcome. I grouped the to-be-displayed data in an object and returned the whole thing from a different helper. This way the object becomes the context of the template and the mustaches directly access attributes of the context-object. In case you wonder: when there is a naming conflict between helper function and context attribute, the helper function wins.

The block helper: ‘{{#with …}}’ sets the context inside the block to the specified value (or return value of the called helper function). In a nested structure of templates you could achieve the same result by changing the HTML-file to this:

The ‘carBody’-template doesn’t have any helper methods. They are not necessary. The invocation of the template: ‘{{> carBody fullcar}}’ sets it’s context to the object we get from the ‘fullCar’-helper method, registered at the ‘car’-template and can subsequently access its properties simply by calling them. Still easy and straightforward.

Simple Nesting

What about more complex objects and accessing the parent context?

The ‘{{#unless}}’-block, which basically means ‘{{#if not}}’ is quite self-explanatory. The only thing that I didn’t get instantly was, that you can’t use comparisons. You simply have to call a helper function or access an attribute and if it evaluates to false then the unless-branch is taken, otherwise an optional else-branch. The same is true for ‘{{#if}}’ blocks, the logic is simply reversed. You can use it with ‘{{else}}’ this way:

Take special notice of the ‘{{../make}}’ notation in the first gist of this section. The dots allow you to access the parent context, like parent folders in the file-system. The double-dot is not always available, meaning it doesn’t always reference to the parent context. While it works with: {{#with …}} it doesn’t work, the way it is implemented in the following gist:

When you pass the context to the template while it is instantiated, it forgets or never knows about the parent context. If you don’t specifically pass something the context of the caller (‘this’) is passed. When you first pass the full context and then later select sub-parts with ‘{{#with …}}’ you have access to the parent context inside it. It took me a while to figure that out.

Collection Elements as Values of a Select-Element

Another stumbling block were collections. Look at the following model:

Imagine I want to create a dropdown-box in the view from the ‘wheels’-values of the model. That seems at first quite easy using the ‘{{#each}}’ block:

So far so good, but what about selecting the right value as defined in the objects root-level attribute ‘selectedWheel’. At first I tried to solve it with conditional logic and simply comparing the value of ‘this’ with ‘../selectedWheel’. That didn’t work because you cannot actually compare values and act on the comparison inside a template (I already mentioned that above). This restriction is consciously in place, to constrain the amount of logic you can put in a template.

Inside a ‘{{#each}}’-block you actually have access to the parent context. I tried to move the actual comparison to a helper function and still use an ‘if’ inside the template. The next gist shows the corresponding code.

Bildschirmfoto 2013-03-16 um 13.20.06

Sadly this evaluates to broken HTML. The picture on the right shows the outcome and the next gist shows the generated HTML code. I don’t exactly understand why this happens.

To circumvent this, I decided to let the helper method deliver the ‘selected’-attribute as a simple string or an empty string in case the element is not selected. That finally worked. The next gist shows the code.

Collection Elements in Separate Templates

If you think this was cumbersome, hold your breath for the final. I encountered for now, two more scenarios, while working on the structure of my user interface. The next scenario is simple and works as, at least I, expected. I tend to mentally connect it with loose coupling in object oriented programming. Let me try to explain why.

Imagine a context-object with self contained parts, or identifiers, that can be used to retrieve the full parts elsewhere. Each part is handed down to a template specifically designed to lay that part out. The part becomes the context-object in the target template. The target template lacks the possibility to access the originating context, since the template, per definition don’t care about its origin. The origin might even be different in different situations.

In OO speak: Receive pointers to aggregate or entity objects (or object ids) from a call to a composite object. Those received objects, don’t have a reference to the composite object that delivered them. They again might be referenced in many different composites.

The next gist shows the code for handling collections of loosely coupled objects:

Remember the case from above: when instantiating a new template the parent context is lost, so you have no chance to access the ‘car’-context from the ‘wheel’-template.

Collection Elements in Separate Templates – with Access to the Parent Context

You sometimes need strong coupling – when the parts of the object are meaningless without their container, for example. In times like this – and I could imagine further scenarios – you might need access to the whole object, to the parent context. The ‘..’-access doesn’t work in Meteor and it doesn’t work in plain Handlebars. I searched a while and found many other developers complaining about it. There are feature requests, issues and some fuss about the right way to access the parent context. This one wants to make the ‘..’-context available in templates (you often find the name ‘partial’, which I treat interchangeably with template).

After some research, trials and thinking I found a solution I can live with. Whenever I need access to the parent context in a template. I wrap the parent context together with the current element in a new object. I then hand this object down to the template, as its context, utilizing a helper method. The next gist shows this. (I know the example gets less and less meaningful.)

I thought about generalizing this, so that ‘..’ becomes the identifier of the parent context as well as ‘this’ points to the element itself. But first, I actually have no idea, how I could achieve this and second I feel safer, to have to specifically treat such situations. Otherwise I fear to find myself soon in a ‘../../../../’-multi-level-value-accessing-hell, discussed here as well.

That’s it. I feel a little more comfortable now and I think I have covered all necessary use cases. But I think it is unavoidable that I get stuck again. In case this happens and I find a proper solution, I will share my new findings here.

Advertisements

One thought on “Structuring Meteor-resque Handlebars-Templates

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s