Qvatra
Qvatra

Reputation: 3847

Polymer 1.5 How to notify dom-repeat when using immutable data structure

Problem: we're using redux to manage state in our app. This is causing issues in the rendering. Changes in arrays (f.e. remove) are not correctly handled by the dom-repeater. What happens is that data and the stamped-templates are getting mixed up.

I want to find a way to notify dom-repeat element about array changes.

<template is="dom-repeat" items="[[data.items]]">
    <repeater-item config="[[item]]" on-change="_onChange"></repeater-item>
</template>

I have immutable state in my Polymer application so I can not use Polymer array mutation methods.

here is a plnkr

What have I tried:
1) this.set('data', newState);
As a result if I will remove the first item in my data array 'dom-repeat' will remove the last template <repeater-item> and will reassign data like this:

template-1 receives data 2,
template-2 receives data 3,
...

2) in second attempt I'm trying to notifySplices:

var splices = Polymer.ArraySplice.calculateSplices(newState.items, this.data.items);
this.data = newState;
this.notifySplices('data.items', splices);

result is the same

3) For some reason the following almost works..

var splices = Polymer.ArraySplice.calculateSplices(newState.items, this.data.items);
this.data.items = newState.items;
this.notifySplices('data.items', splices);

this results in a correct template removal but here I receive an error:

VM47184 polymer-mini.html:2046 Uncaught TypeError: Cannot read property 'length' of undefined

What is the correct way of notifying 'dom-repeat' if using immutable state?

Upvotes: 2

Views: 362

Answers (1)

Chris van Leeuwen
Chris van Leeuwen

Reputation: 86

I've been able to prevent the error for option 3; adding Polymer.Collection.get for the new array seems to prevent the error which occurs after the method completes and dom-repeat renders the changes.

_remove(id) {
  var newState = {
    items: this.data.items.filter(item => item.id !== id)
  };

  // Polymer.Collection.get somehow prevents an exception _after_ notifySplices is called
  Polymer.Collection.get(newState.items);

  // Retro-actively calculate splices in Polymer fashion
  var prev = (this.data.items || []);
  var splices = Polymer.ArraySplice.calculateSplices(newState.items, prev);

  // Change the data _without_ Polymer being aware of it (because it isn't a direct property of the element)
  this.data.items = newState.items;

  // Notify Polymer about the array changes so dom-repeat can re-use the correct templates
  this.notifySplices('data.items', splices);
}

See it in action: http://plnkr.co/edit/fFGWfL?p=preview

I don't know why this prevents the exception, it was more of a accidental discovery more than anything else.

But this still seems like a sub-optimal solution, since you have to hide the affected array in a wrapper object.

Upvotes: 1

Related Questions