130

Is there a way in Handlebars.js templating to check if the collection or list is null or empty, before going and iterating through the list/collection?

// if list is empty do some rendering ... otherwise do the normal
{{#list items}}

{{/list}}



{{#each items}}

{{/each}}
Drejc
  • 13,466
  • 15
  • 65
  • 101

5 Answers5

247

If you have something that you want to display once and only if the array has data, use

{{#if items.length}}
    //Render
{{/if}}

.length will return 0 for empty arrays so we have achieved a real falsey value.

Christian Neverdal
  • 4,815
  • 5
  • 32
  • 87
Duane
  • 4,161
  • 1
  • 22
  • 26
  • 1
    Both answers are correct and work, and they answer the question. Which was how to display something when there is no data in the array. Not the other way around. – Drejc Feb 07 '14 at 22:00
  • 16
    No i agree, this is the correct answer. It doesn't include a for loop. – radtek Oct 18 '14 at 20:59
  • 4
    Simple case: I want to render an `
      ` tag once and an `
    • ` tag for each item in the list. If the list is empty I don't even want the `
        ` to render, and rendering something else like `

        empty list

        ` inside the `

          ` doesn't make sense.
    – Fuad Saud Mar 24 '15 at 23:18
  • If you are working in Ember.js it doesn't seem to work. I'm wondering if it has something to do with Ember.js's custom arrays. – Ash Blue Oct 21 '15 at 01:11
  • 2
    This answer is implementation specific. The [handlebars docs](http://handlebarsjs.com/builtin_helpers.html#conditionals) specify that `[]` is evaluated as false. The answer by @Drejc is the correct answer by handlebar specification. – Stim Mar 14 '16 at 14:01
  • 1
    thank you dude that is way better solution than registerHelper. – Danish Jan 30 '17 at 14:06
219

The "each" tag can take an "else" section too. So the simplest form is:

{{#each items}}
// render item
{{else}}
// render empty
{{/each}}
Emre Efendi
  • 2,447
  • 1
  • 13
  • 5
  • 2
    That's cool, but doesn't answer the question. If you want a tag to wrap `#each`, like an `
      ` tag (with `
    • `s inside), you don't want the empty state to be wrapped by the `
        `.
    – Leonardo Raele Jul 15 '19 at 20:41
38

Ok it's simpler than I thought:

{{#if items}}
// render items

{{#each items}}
// render item
{{/each}}

{{else}}
// render empty
{{/if}}
Drejc
  • 13,466
  • 15
  • 65
  • 101
  • 5
    If `items` is an empty array (i.e. has a value of `[]`), it will produce a truthy value. Whereas `items.length` produces a falsey value for an empty array. See [@Duane's answer](http://stackoverflow.com/questions/10381827/handlerbars-js-check-if-list-is-empty/21611066#21611066). – gfullam Dec 09 '15 at 20:02
  • Huh ... 3 years have past since ... it might be that the implementation has changed or that I simple had no case of [] array. As far as I recall it worked for me. – Drejc Dec 10 '15 at 20:19
  • 13
    You're right. I preemptively commented based on the behavior of native JS' `if`, but the [Handlebars documentation](http://handlebarsjs.com/builtin_helpers.html#conditionals) is very clear: "If its argument returns `false`, `undefined`, `null`, `""`, `0`, or `[]`, Handlebars will not render the block." I should have checked the docs first. – gfullam Dec 11 '15 at 14:43
8

If you want to check if a collection (cursor) is empty or not, the previous answers won't be useful, instead you must use the count() method :

{{#if items.count}}
    <p>There is {{items.count}} item(s).</p>
{{else}}
    <p>There is nothing</p>
{{/if}}
Karl.S
  • 1,716
  • 1
  • 18
  • 31
2

For anyone who needs to use an {{#each}} on top of {{#if}} (i.e. an if loop inside a for loop). Is they have three different list of arrays.

Using a lookup inside a if statement solves the issue for me. As, the above answers did not solve my issue.

Here is my code,

{{#each OtherRandomItems}}

  {{this}}

  {{lookup ../AnotherRandomItems @index}}

  {{#if (lookup ../RandomItems @index)}}
  // render items
  {{else}}
  // render empty
  {{/if}}

{{/each}}
Akarsh SEGGEMU
  • 1,273
  • 9
  • 15