New Glimmer consideration: #each key=

I’m in the processing of upgrading lots of components to glimmer.

I’ve noticed subtle differences around the {{each}} helper:

When the array changes, each component in the loop is rendered as expected:
Pre glimmer: Ember each rendering - JSFiddle - Code Playground

When the array changes, nothing happens
Glimmer: Ember render bug - JSFiddle - Code Playground

This is solved by adding key='id' to the each helper.

I get that this is react-style rendering in action, but my questions are:

  • Why was this never mentioned?
  • What is the rule of thumb for using it?

You should have thing as a dependant key on your computed property… That also fixes it.

@jmurphyau Yes that would also fix it. But that’s not the same.

That would imply to developers / users of the component that the properties need to re-compute. But they don’t. The component is a one-time only thing.

There’s an open issue to document key in each: https://github.com/emberjs/ember.js/issues/11117

What surprised me was the requirement that the key must be a string. Otherwise you get a ‘Uncaught Error: You must provide a string key when calling yieldItem; you provided 1’

Shouldn’t at least numbers be accepted as well? In my app messages that I show with #each have unique gids that are numbers. As a workaround I created a computed property that just converts them to strings. Would be nice to not need it.

@ilkkao Numbers are accepted if you pass one in: key=number will be cast to a string. key='foo.bar' uses the path directly. (thanks for the link, wish I’d found that sooner).

[Edit: incorrect]

@ilkkao I’ve later learned that although key=number and key='foo.bar' both result in strings. They are not the same. Using the ‘path’ format is more reliable

There was some discussion in the Slack community about this. It was decided that it should really work with an integer value because it is so common.

https://github.com/emberjs/ember.js/issues/11343

1 Like

Nice to hear. @amk thanks for proposing it.

Added in [BUGFIX beta] Add special values to `{{each}}`'s keyPath. by rwjblue · Pull Request #11339 · emberjs/ember.js · GitHub.

Also added some documentation (copy/paste follows):

key param

The key hash parameter provides much needed insight into how the rendering engine should determine if a given iteration of the loop matches a previous one. This is mostly apparent during re-rendering when the array being iterated may have changed (via sort, removal, addition, etc).

For example, using the following:

  {{#each model key="id" as |item|}}
  {{/each}}

Upon re-render, the rendering engine will match up the previously rendered items (and reorder the generated DOM elements) based on each item’s id property.

There are a few special values for key:

  • @index - The index of the item in the array.
  • @item - The item in the array itself. This can only be used for arrays of strings or numbers.
  • @guid - Generate a unique identifier for each object (uses Ember.guidFor).
1 Like

Many of the issues that existed in the initial implementation (in 1.13.0) have been fixed, and it is now unlikely that you have to provide a key= option at all. By default the items own reference (Ember.guidFor(item) if it is an object or the value if it is a primitive value).

See Ember - 4.6 - Ember API Documentation for details.

3 Likes