Array manager component?


#1

Hello emberistas!

We recently put together a component to manage an array (add/update/remove strings from the array) and found some unexpected rendering behavior. We were able to work around it, however I felt that our initial approach should have worked. That approach was as follows:

  • In didReceiveAttrs, add an empty string for a new item
  • On input, update the item and (if editing the last item, add a new empty string)
  • On change, remove empty items
  • (elsewhere, remove empty strings)

Here’s a twiddle that demonstrates the weirdness that ensues. Note the way the array renders in the list after trying to add a new item.


#2

{{#each}} needs some concept of identity to decide what parts of your list are stable and which have changed. By default, it just uses ===. (If you pass key to each it will use that property on each item instead.)

You want each input element to have an identity that remains constant even when the contents change. So you can’t use the values themselves as the list items: you need some containing objects.

Here’s a fixed version that represents the list as [{ value: 'a'}, { value: 'b'}]: https://ember-twiddle.com/0e4040890fd70d8dad029b208bae512b?openFiles=components.input-list.js%2Ctemplates.components.input-list.hbs

It works because the items in the list retain their identities during editing.


#3

Awesome thanks @ef4! Somehow I suspected it was something like this but I didn’t try it with objects. So your your explanation is very much appreciated!

So would you say what is happening in my Twiddle (with raw strings) is basically that the rendering is “unstable” or something? I found it odd that the input didn’t lose focus. Does glimmer guard against re-rendering an item with focus?