Polymer 2.x:dom-repeat没有观察到计算数组的子节点

时间:2018-02-20 20:18:03

标签: javascript polymer polymer-2.x

我有一个dom-repeat和另一个dom-repeat嵌套在里面。外部绑定到计算数组。当我对父数组进行更改时,会观察到更改(意味着会触发观察者代码),但更改不会反映在UI / dom-repeat中。

以下是我的代码示例。单击第二个div内的dom-repeat触发函数handleItemTap,然后对父数组进行更改。然后观察这种变化,重新计算计算出的数组;但是,将IsChecked添加到父对象不会影响UI中的复选框,该复选框应该绑定到IsChecked属性。我做错了什么?

<template is="dom-repeat"
          items="[[outerComputedArray]]" as="group"
          id="groupRepeater">
    <div class="group-container">       
        <template is="dom-repeat"
                  items="[[group.InnerArray]]" as="sesh">
            <div on-tap="handleItemTap">
                <paper-checkbox id="paperCheckboxId"
                                checked="[[sesh.IsChecked]]"></paper-checkbox>
            </div>
        </template>
    </div>
</template>

...

static get properties() {
    return {
        'parentArray': Array,
        'outerComputedArray': {
            type: Array,
            computed: 'computeOuterArray(parentArray.*)'
        }
    }
}

computeOuterArray(parentArray) {
    if (!(typeof parentArray.base === 'undefined' || parentArray.base == null || parentArray.base.length == 0)) {
        let groupedGrid = parentArray.base.reduce((a, b) => {
            a = a || [];
            let idx = a.findIndex(x => x.PaymentType == b.PaymentType);
            if (idx == -1) {
                let newArray = [];
                newArray.push(b);
                a.push({ 'PaymentType': b.PaymentType, 'InnerArray': newArray });
            }
            else {
                a[idx].InnerArray.push(b);
            }
            return a;
        }, []).map(x => {
            x.Total = x.InnerArray.map(y => y.TotalAmount).reduce((a, b) => a + b, 0);
            return x;
        });
        groupedGrid.sort((a, b) => a.PaymentType.localeCompare(b.PaymentType));

        return groupedGrid;
    }

    return [];
}

handleItemTap(e) {
    let idx = this.parentArray.findIndex(x => x.id == e.model.sesh.id);
    this.set(`parentArray.${idx}.IsChecked`, !(!!e.model.sesh.IsChecked));
}

2 个答案:

答案 0 :(得分:0)

看起来像Polymer对象脏检查是这里的问题。它用于加速Polymer,但有时脏检查不起作用(例如,当您更改数组中的元素时)。 要绕过它,您需要使用mutable data mixin

首先,您需要在声明元素时引入mixin。

class MyMutableElement extends Polymer.MutableData(Polymer.Element) { ... }

您还需要将mutable-data标志添加到dom-repeat。

<template is="dom-repeat" items="[[outerComputedArray]]" as="group" id="groupRepeater" mutable-data>

如果它仍然不起作用,请尝试在computeOuterArray函数的末尾添加这样的内容(但仅当您实际更改数组时)。

timeout(() => { this.notifyPath('outerComputedArray') }, 10)

答案 1 :(得分:0)

我非常感谢@ mary-shaw试图提供帮助,但我无法将这些建议付诸实施。这就是我现在提出的问题。我已经在outerComputedArray上放置一个观察者来更新第二个数组 - 一个名为selectedIds的新属性 - 包含已更改属性IsChecked的所有项目。然后,我添加了另一个计算函数,用于检查selectedIds是否与最里面的id中的对象具有相同的dom-repeat属性。

<template is="dom-repeat"
          items="[[outerComputedArray]]" as="group">
    <div class="group-container">       
        <template is="dom-repeat"
                  items="[[group.InnerArray]]" as="sesh">
            <div on-tap="handleItemTap">
                <paper-checkbox id="paperCheckboxId"
                                checked="[[computeIsChecked(selectedIds.*, sesh.id)]]"></paper-checkbox>
            </div>
        </template>
    </div>
</template>

...
<script>
    static get properties() {
        return {
            'parentArray': Array,
            'outerComputedArray': {
                type: Array,
                computed: 'computeOuterArray(parentArray.*)'
            },
            'selectedIds': Array
        }
    }

    static get observers() {
        return [
            'onOuterComputedArrayChanged(outerComputedArray.*)'
        ]
    }

    onOuterComputedArrayChanged(outerComputedArray) {
        if (!(typeof outerComputedArray.base === 'undefined' || outerComputedArray.base == null || outerComputedArray.base.length == 0)) {
            this.set('selectedIds', outerComputedArray.base.filter(x => x.InnerArray.some(y => !!y.IsChecked)).map(x => x.InnerArray.filter(y => !!y.IsChecked)).reduce((a, b) => a.concat(b), []).map(x => x.id));
        }
    }

    computeIsChecked(selectedIds, id) {
        if (!(typeof selectedIds.base === 'undefined' || selectedIds.base == null || selectedIds.base.length == 0)) {
            return selectedIds.base.some(x => x == id);
        }

        return !!0;
    }

    computeOuterArray(parentArray) {
        if (!(typeof parentArray.base === 'undefined' || parentArray.base == null || parentArray.base.length == 0)) {
            let groupedGrid = parentArray.base.reduce((a, b) => {
                a = a || [];
                let idx = a.findIndex(x => x.PaymentType == b.PaymentType);
                if (idx == -1) {
                    let newArray = [];
                    newArray.push(b);
                    a.push({ 'PaymentType': b.PaymentType, 'InnerArray': newArray });
                }
                else {
                    a[idx].InnerArray.push(b);
                }
                return a;
            }, []).map(x => {
                x.Total = x.InnerArray.map(y => y.TotalAmount).reduce((a, b) => a + b, 0);
                return x;
            });
            groupedGrid.sort((a, b) => a.PaymentType.localeCompare(b.PaymentType));

            return groupedGrid;
        }

        return [];
    }

    handleItemTap(e) {
        let idx = this.parentArray.findIndex(x => x.id == e.model.sesh.id);
        this.set(`parentArray.${idx}.IsChecked`, !(!!e.model.sesh.IsChecked));
    }
</script>