Search code examples
handlebars.jshandlebarshelper

What's a clean way to have a conditional container in handlebars?


When there is a link present, we want something like this HTML:

<a href="{{url}}" title="{{title}}" target="_blank"><img src="{{src}}"></img></a>

When there is no link present, we want something like this HTML:

<img src="{{src}}"></img>

Is there a clean way to do this? I consider the following solution bad, because it's dangerous to have to separately remember to open and close the <a> tag:

{{#if url}}<a href="{{url}}" title="{{title}}" target="_blank">{{/if}}
  <img src="{{src}}">
{{#if url}}</a>{{/if}}

I considered using a block helper, but can't think of how to do so without adding more complexity. Maybe something like:

{{#linkWrap url}}<img src="{{src}}">{{/linkWrap}}

But then it's hard to see how we set the title and target and everything gets awkward.


Solution

  • I think you are on the right track, but I would recommend using a Handlebars Partial Block instead of a Block Helper. This will allow to pass one piece of template (the block) to another piece of template by which it will be wrapped (the partial).

    Handlebars provides us with {{> @partial-block }} as a way to render a block of template within a partial. We can use this to create our "linkWrap" partial:

    {{#if link}}
        <a href="{{link.url}}" target="{{link.target}}" title="{{link.title}}">
            {{> @partial-block}}
        </a>
    {{else}}
        {{> @partial-block}}
    {{/if}}
    

    This gives us a clean and simple partial that will allow us to wrap any section of our template with a link as long as we have a link object to pass to our partial. Note that I have opted to use an object to represent the link so that I can pass a single parameter to the partial instead of passing the url, title, etc. properties individually.

    For anywhere we wish to render a link around some markup in our template, we can do so in the following way:

    {{#> linkWrap link=link}}
        <img src="{{image.src}}">
    {{/linkWrap}}
    

    If the link object is null or undefined, the img element will be rendered without a parent anchor element.

    I have created a supplementary fiddle for reference.