Iterate over a list, use index to fetch item from another list, pass in to nested component


#1

A component needs to be fed items at the same index from 2 associated arrays, list1 & list2. How can I access an item from an array at an interpolated index inside a Handlebars expression?

Loop initialisation:

{{#each list1 as | item index |}}
  {{! loop body}}
{{/each}}

As a preliminary sanity check, I can confirm that the list is accessible, and querying it with literal indices using this delightful syntax will work:

{{log list2.[0]}}

But the following loop bodies will throw template parser errors:

{{log list2[index]}}
{{log list2.@index]}}

The following don’t output anything:

{{log list2.[index]}}
{{log list2.index}}
{{log list2.[@index]}}

On further reading, the get helper as a nested expression seems appropriate, but these didn’t give me any luck:

{{log (get figures index)}}
{{log (get figures @index)}}

Any other ideas?


#2

I was lucky to get a thorough analysis of this problem from @rwjblue over on the Slack room. He pointed me to a Twiddle demonstrating the use of a helper to access interpolated indices on an array.

For posterity, here are failing test cases demonstrating the inability of the built-in get helper to access interpolated indices of an array, or indeed number-like keys from an object.

Handlebars’ minimal built-in helpers (and Ember’s minimal extensions) indicate a philosophy whereby view logic should be kept to a minimum, but I’d argue that having to integrate extra code into your codebase to do something as simple as this is adding far too much complexity.

Shouldn’t this be built in to get by default? Doesn’t this qualify as a bug?

import Ember from 'ember';

export function getAtIndex(params/*, hash*/) {
  return params;
}

export default Ember.Helper.extend({
  recomputeOnArrayChange: Ember.observer('_array.[]', function() {
    this.recompute();
  }),

  compute([array, index]) {
    this.set('_array', array);

    return array.objectAt(index);
  }
});

#3

One problem with changing the present behaviour is that it would be a breaking change.

A possibility is to make a souped up get helper available as an addon, and if you’re using Ember CLI it should be a matter of running the install command to set it up.


#4

Could you be more specific? I honestly can’t imagine what kind of scenario would fail after making this work according to the expectations laid out above.

IMO this test should at least be respecified ‘Object literal’ (actually, as I showed in the second test case, this assertion isn’t bulletproof) and ideally would be complemented by a test for Arrays (if not Maps & WeakMaps).