Looping Through Lists - First and Last

I’m aware of the Looping Through Lists in the documentation but it does not cover how to handle the first and last element in the list if they need special treatment.

Problem description

Given a list like

['apple', 'banana', 'plum']

how to produce

apple, banana and plum

Previous research

Handlebars has @first and @last but they don’t work in Ember.

Starting with ember-source@3.28, you can use GitHub - ember-template-imports/ember-template-imports: Template import support in Ember! to use the Polaris-style way of authoring components.

So,

// some-component.gjs
const fruits = ['apple', 'banana', 'plum'];
const isFirst = (fruit) => fruit === fruits[0];
const isLast = (fruit) => fruit === fruits[fruits.length - 1];

<template>
  {{#each fruits as |fruit|}}
    <div 
      class="fruit 
             {{if (isFirst fruit) 'first'}} 
             {{if (isLast fruit) 'last'}}
            "
    >
      {{fruit}}
    </div>
  {{/each}}
</template>

One important distinction about ember is that it doesn’t use handlebars – it shares an extension, so people will often call the templates the same thing, but it’s more handlebars-inspired, so using handlebarsjs.com isn’t gonna be a good time for the average learner.

for gjs/gts aka <template>, I recommend: https://tutorial.glimdown.com

2 Likes

This is a good question and something that doesn’t have a super satisfactory answer, but there are a few options.

For more sophisticated scenarios, or very specific use cases, you could write your own custom helper to assist you (note this is modern syntax with template imports):

const listFruits = (fruits) => `${fruits.slice(0,-1).join(', ')} and ${fruits.slice(-1)}`;

<template>
  {{listFruits @fruits}}
</template>

For simpler scenarios you could do something like (some of these helpers are from ember-truth-helpers and ember-math-helpers):

{{#each fruits as |fruit index|}}
  {{#let
    (eq index 0)
    (lt index fruits.length)
    (eq index (sub fruits.length 1))
    as |isFirst isNotLast isLast|
  }}
    {{if isLast "and"}}
    {{fruit}}
    {{~if isNotLast ','}}
  {{/let}}
{{/each}}
1 Like

For the given example, you may want to consider Intl.ListFormat as well. It could be used inside an helper. Ember Intl provides such a {{format-list}} helper.

2 Likes

Just use the array.at method

1 Like