Polymer - dom-repeat & caching of element data in

2019-07-11 07:39发布

问题:

following scenario: I have a Firebase database containing a list that is used to create a set of "paper-cards" with dom-repeat:

<template is="dom-repeat" items="{{items}}">
  <my-element card="{{item}}">
      <paper-card id="{{card.id}}">
          ...
      </paper-card>
  </my-element>
</template>

In the UI, the user can add or delete paper-cards, so items also get deleted in Firebase.

Now I realized if I change the CSS of an element (e.g. fadeIn, fadeOut animation) and afterwards delete a card and later add one card, the card still has the CSS state as it was before (e.g. for fadeIn/fadeOut animations).

My questions:

  1. How does DOM repeat deal with elements added or removed? Is not all information of this element "deleted"?

  2. If I delete item #5 (out of 10), what happens to elements 6-10, are they deleted and re-created as "5-9" or "moved/altered"?

  3. Besides CSS, are there any other implications that should be considered inside the template tag? Do I need to manually reset anything?

回答1:

The repeater evaluates the number of items in your array on initialization and stamps that many template instances into the DOM. If you delete an item from your array the repeater is presented with a new array that is one element less, removes the last one and propagates data change to elements' instances.

So if you start with 10 elements and order to delete #5 then element's #6 data is inserted via data-binding into the same DOM node that previously contained #5 data, and so on down the list. The last DOM node for which the updated array contains no data will be removed from the DOM tree.



回答2:

You can read about the dom-repeat on https://www.polymer-project.org/1.0/docs/api/dom-repeat but what it basically tells you that it tries to be too smart without asking the developer if it wants that behavior. The dom-repeat is heavily flawed because of this.

Polymer is saving performance to doing a dirty check, basically looping through everything and only changing the DOM if the checked values (id, in this case) changes. This means that it will inherit other values.

Basically, it wont update sub-properties. This means that dom-repeat isn't really made for any kind of update.

You can possibly go around this issue by using Polymer's this.splice(). It works like the splice in javascript but sends out an event to dom-repeat to update and where to update. Remember however, that arrays in Javascript are references, so if you take this.items and try to modify it, it will automatically update values the dom-repeat (without updating DOM) and then it will dirty check the update with the new values and not change anything at all. If you want to modify the array in the dom-repeat, then use JSON.parse(JSON.stringify(array) first to get rid of the reference.

Another thing you can do is to use the unique id. If the id changes for that specific card, then hard reset all values and initialize that specific card once again with all it's normal properties (including CSS). That's the workaround I use all the time.

The desperate thing to do, when nothing else works, is to nullify the array that keeps track of the cardset, with this.set('items', []) and then set the property with the new array.