聚合物数据绑定到属性的奇怪行为

Strange behavior in Polymer data-binding to an attribute

我正在使用 Polymer 1.0 尝试绑定到自定义元素的属性,然后只显示它。

自定义元素实际上是一个 <iron-input> 列表,它有一个添加按钮和一个删除按钮。我想将该列表中的任何更改反映给主持人。它还有一个 minItemSize 属性,这意味着它至少有这么多元素。所以我向观察者添加了一个检查,添加了额外的元素以防它低于这个数字。

但是当我绑定到包含列表的属性时,事情变得不同步,我可以从 ui.

中删除所有输入

我有两个 <dyn-inputlist> 元素。在其中一个中,我没有绑定到 data 属性,另一个我做。

第一个行为符合预期:在单击按钮时添加和删除。

另一个不行,因为你可以去掉所有的输入框。尽管数据本身已更新,并填充了额外的项目,但出于某种原因 UI 并未反映这一点。 (检查元素的数据 属性 确实表明它具有正确的项目数)

我还希望如果我在两个 dyn-inputlist 元素上设置 data={{myData}},它们总是显示相同的内容。但是随机按任一组件上的 add/remove 按钮会使它们不同步。

我错过了什么吗? 提前致谢。

index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="components/dyn-inputlist.html"/>
</head>
<body>

<template is="dom-bind">
    <dyn-inputlist min-item-size="4"></dyn-inputlist>
    <div>{{mydata}}</div>
    <dyn-inputlist min-item-size="4" data="{{mydata}}"></dyn-inputlist>
</template>

</body>
</html>

dyn-inputlist.html:

<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../../iron-input/iron-input.html">

<dom-module id="dyn-inputlist">
    <template>
        <button on-click="removeItem">x</button>
        <button on-click="addItem">+</button>
        <template is="dom-repeat" items="{{data}}">
            <div>
                <span>{{index}}</span>
                <input is="iron-input" bind-value="{{item.content}}">
            </div>
        </template>
    </template>
    <script>
        Polymer({
            is: 'dyn-inputlist',
            properties: {
                minItemSize: {
                    type: Number,
                    notify: true,
                    value: 1
                },
                data: {
                    type: Array,
                    reflectToAttribute: true,
                    notify: true,
                    value: function () {
                        return []
                    }
                }
            },

            observers: ['_dataChanged(data.*)'],

            addItem: function (e) {
                this.unshift('data', {content: ""});
                this.reflectPropertyToAttribute('data')
            },

            removeItem: function (e) {
                this.shift('data');
                this.reflectPropertyToAttribute('data')
            },

            _dataChanged: function (e) {
                if (this.data != null) {
                    while (this.data.length < this.minItemSize) {
                        this.push('data', {content: ""})
                    }
                } else {
                    this.data = [{content: ""}];
                }
                this.reflectPropertyToAttribute('data');
            }

        });
    </script>
</dom-module>

编辑: 这是实时代码:http://jsbin.com/poquke/1/edit?html,output

我试了一下你的代码,我注意到如果你将代码包装在你更改过的处理程序中的异步函数中,它就会起作用。这解决了您描述的两个问题。

_dataChanged: function (e) {
    this.async(function(){
        if (this.data != null) {

            while (this.data.length < this.minItemSize) {
                this.push('data', {content: ""})
            }
        } else {
            this.data = [{content: ""}];
        }
    });
}

对于这种行为,我没有一个完美的解释。我假设它与 Polymer 处理变化观察的方式有关。每次您推送到已更改处理程序中的数据数组时,这实际上会更改数据并且应该再次触发处理程序。

简化的话就不需要async了。

这是简化的代码,这消除了当您推送最小值时对 _dataChanged 的​​重复调用,并允许 polymer 的内置事件系统负责更新和通知其他元素。函数:_createNewItem() 用于创建对象。这简化了处理项目对象创建的位置。

http://jsbin.com/vemita/6/edit?html,output

link 和 URL 引用已从上述问题中的示例代码更改为符合与 polyserve 一起使用的聚合物元素和演示页面标准。

我已经对您的原始代码进行了评论,以了解为什么每一行都应该或不应该在那里。这包括更改 _dataChanged

的原因

http://jsbin.com/ponafoxade/1/edit?html,output