G Mawr
G Mawr

Reputation: 1183

Mustache templates: How to output a block only once for non-empty lists

If my list is empty, I want to output this:

<div id="some-id">
</div>

If my list is non-empty, I want to output this:

<div id="some-id">
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>etc</li>
  </ul>
</div>

Note that I output the <ul> and </ul> tags at most once, and only if the list is non-empty.

The following code is close to how I would do this in PHP, but is obviously wrong:

<div id="some-id">
{{#items}}
  <ul>
{{/items}}

{{#items}}
    <li>{{name}}</li>
{{/items}}

{{#items}}
  </ul>
{{/items}}
</div>

If items is a 3 item list, I'm going to get 3 <ul>'s - obviously not what I want.

I realise I could set some other key as a boolean flag (hasItems, perhaps), but this feels redundant.

Is there a more elegant way I can output a block only once for a non-empty list?

Upvotes: 20

Views: 6756

Answers (3)

endemic
endemic

Reputation: 1366

The other two answers do not work for the Ruby implementation of Mustache. My solution was to send an additional parameter as part of the template context; e.g.

template = <<EOF
{{#has_items}}
<ul>
    {{#items}}
        <li>{{.}}</li>
    {{/items}}
</ul>
{{/has_items}}
EOF
items = ['one', 'two', 'three']
context = { items: items, has_items: items.any? }
Mustache.render(template, context)

Upvotes: 1

broox
broox

Reputation: 3960

If you don't want to or can't reformat your data or templating engine, you can also just check items.length before rendering the <ul> tags. Some people frown upon this, but it's definitely an alternative to Max's answer.

{{#items.length}}
    <ul>
        {{items}}
            <li>{{name}}</li>
        {{/items}}
    </ul>
{{/items.length}}

Upvotes: 18

maxbeatty
maxbeatty

Reputation: 9325

You could use non-false values of a section. name would have to be an object inside of items

data = { 'items' : { 'name' : ["Item 1", "Item 2", "etc"] } };

You template would look like:

<div id="some-id">
    {{#items}}
    <ul>
        {{#name}}
        <li>{{.}}</li>
        {{/name}}
    </ul>
    {{/items}}
</div>

Here's an example on jsFiddle showing the rendering of an items object with names and without -- http://jsfiddle.net/maxbeatty/fpQwk/

Upvotes: 6

Related Questions