polymer-redux
polymer-redux copied to clipboard
redux state array bound to dom-repeat doesn't reflect items property changes.
I have the following element the issue is when changing an employee thru redux action, the changes does not propagate to the dom-repeat, but is reflected when bound directly inside the parent template (e.g. [[employees.0.id]]) I've tried manual re-render of the dom-repeat template e.g. this.$.employees.render() but still does not reflect the updated employee properties any suggestion?
Note: i'm using v1.01
<dom-module id="employees-info">
<template>
[[employees.0.id]] - [[employees.0.firstname]] -- [[employees.0.lastname]]
[[employees.1.id]] - [[employees.1.firstname]] -- [[employees.1.lastname]]
<template is="dom-repeat" items=[[employees]] as=“employee” id=“employees” >
<div>id: [[employee.id]]</div>
<div>firstname: [[employee.firstname]]</div>
<div>lastname: [[employee.lastname]]</div>
</template>
</template>
<script>
class EmployeesInfo extends ReduxMixin(Subscriber(Polymer.Element)) {
static get is() {
return 'employees-info'
}
static get properties() {
return {
employees:{
type:Array,
statePath:'employees'
}
}
}
}
customElements.define(EmployeesInfo.is, EmployeesInfo);
</script>
</dom-module>
Now inside the redux store actions, (i've already tried multiple ways to update the array e.g. splice)
```
case 'UPDATE_EMPLOYEE_SUCCESS':
return Object.assign({}, state, {
employees: state.employees.slice().map((employee) =>{
// update employee bere
return employee;
}), updating_employee: 'success' });
Plus one this issue. I am facing the same problem. sub properties are not notified on change.
I am facing the same issue. The data is definitely updating and observers are firing ... but nothing is happening inside the dom-template.
static get observers() {
return [
'_test(myArray.*)',
];
}
_test(change) {
// this all works ...
console.info(change);
console.info(this.get('myArray.0.items.length'));
}
For reasons beyond my understanding, this seems to trigger something to make the dom-repeat update
static get observers() {
return [
'_updateNotifier(myArray.*)',
];
}
_updateNotifier(change) {
change.base.forEach((base, i) => {
this.notifyPath(`${change.path}.${i}.items.length`);
});
}
I had the same problem and @pixelass "fixed" it by using https://github.com/kolodny/immutability-helper instead of dealing with state changes on our own (even when we thought that we are creating immutable data):
const myArray = [{ name: 'foo' }, { name: 'bar' }]
const newMyArray = update(myArray, { 0: { $set: { name: 'foobar' } } })
Note: We are using Polymer 3 and https://github.com/tur-nr/polymer-redux/tree/polymer-3 and https://github.com/NERDDISCO/immutability-helper/ because of ES6 modules
On Polymer 2 there is another solution. It's to use "mutable-data" in the template dom-repeat.
<template is="dom-repeat" items="[[todos]]" as="todo" mutable-data>
[[todo.completed]]
</template>
The problem i found is to notify changes to children elements of the dom-repeat. Like this:
<template is="dom-repeat" items="[[todos]]" as="todo" mutable-data>
<todo-item todo="[[todo]]" index="[[index]]"></todo-item>
</template>
In this case <todo-item>
do not change, even of the mutable-data configuration on dom-repeat. This situation is solved using the Polymer.MutableData mixin on <todo-item>
.
class TodoItem extends Polymer.MutableData(ReduxMixin(Polymer.Element)) {
// all the element code remains without changes
}
I dont know the performance of this solution. (Worried because with any minimal change in the array causes a notification of change in all the items in the dom-repeat, even if only has changed one of them)
This worked perfect for me with immutable-js/redux, including only rending the items that have changed. FYI, I'm using Polymer 3
You need to implement helper methods for calling the immutable methods. I implemented them it as a mixin for obvious reasons....
import Immutable from 'immutable';
export default (Parent) => {
return class ImmutableMixin extends Parent {
_getFromImmutable(instance, key) {
return instance.get(key);
}
_getInImmutable(instance, searchKeyPath) {
return instance.getIn(searchKeyPath);
}
_hasFromImmutable(instance, key) {
return instance.has(key);
}
_hasInImmutable(instance, searchKeyPath) {
return instance.hasIn(searchKeyPath);
}
_firstFromImmutable(instance) {
return instance.first()
}
_lastFromImmutable(instance) {
return instance.last();
}
_toArrayFromImmutable(instance) {
return instance.toArray();
}
_toObjectFromImmutable(instance) {
return instance.toObject();
}
}
}
You then use these in your template to dynamically generate a shallow JS array from the immutable list, and use get
or getIn
if the items are immutable objects to get the values.
static get template() {
return html`
<h1>Polymer with Webpack example</h1>
<a href="#" on-click="_handleClick">Search!</a>
<div>
<h2>Results</h2>
<template is="dom-if" if={{results.size}}>
<ul>
<template is="dom-repeat" items="[[_toArrayFromImmutable(results)]]" as="item">
[[Immutable.get]]
<li>
<z-toggle active="[[_getFromImmutable(item, 'active')]]" on-active-change="_handleActiveChange">[[_getFromImmutable(item, 'key')]]</z-toggle>
</li>
</template>
</ul>
</template>
</div>
`;
}
I'm probably going to do a starter project that includes this code.
This starter project gives an example https://github.com/zakkudo/polymer-3-starter-project