Reputation: 3847
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.
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
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