New Glimmer consideration: #each key=


#1

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: http://jsfiddle.net/amk221/6mjskzp4/

When the array changes, nothing happens
Glimmer: http://jsfiddle.net/amk221/rehkvtv3/

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?

#2

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


#3

@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.


#4

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.


#5

@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]


#6

@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


#7

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


#8

Nice to hear. @amk thanks for proposing it.


#9

Added in https://github.com/emberjs/ember.js/pull/11339.

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).

#10

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 http://emberjs.com/api/classes/Ember.Templates.helpers.html#toc_specifying-keys for details.