polymer-redux icon indicating copy to clipboard operation
polymer-redux copied to clipboard

redux state array bound to dom-repeat doesn't reflect items property changes.

Open togonow opened this issue 6 years ago • 7 comments

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' });

togonow avatar Sep 14 '17 18:09 togonow

Plus one this issue. I am facing the same problem. sub properties are not notified on change.

jobizzness avatar Oct 15 '17 11:10 jobizzness

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'));
      }

barnomics avatar Dec 01 '17 12:12 barnomics

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`);
        });
      }

barnomics avatar Dec 01 '17 12:12 barnomics

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

TimPietrusky avatar Dec 07 '17 06:12 TimPietrusky

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)

midesweb avatar Mar 23 '18 09:03 midesweb

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.

zakkudo avatar Jun 19 '18 16:06 zakkudo

This starter project gives an example https://github.com/zakkudo/polymer-3-starter-project

zakkudo avatar Jun 28 '18 01:06 zakkudo