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

时间:2015-08-09 11:02:16

标签: javascript html polymer web-component

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

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

但是当我绑定到包含列表的属性时,事情就会失去同步,我可以删除ui中的所有输入。

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

第一个表现符合预期:在按钮点击上添加和删除。

另一个不起作用,因为您可以删除所有输入框。即使数据本身已更新,并且由于某种原因填充了额外的项目,但UI并未反映这一点。 (检查元素的data属性确实显示它具有正确的项目数)

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

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

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

2 个答案:

答案 0 :(得分:0)

我已经玩了一些你的代码,我注意到如果你在异步函数中包装你改变的处理程序中的代码它会工作。这解决了您描述的两个问题。

_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处理观察变化的方式有某种关系。每次在更改的处理程序中推送到数据数组时,这实际上都会更改数据,并且应该再次触发处理程序。

答案 1 :(得分:0)

如果简化,则不需要异步。

这是简化的代码,当你按下最小值时,它会删除对_dataChanged的重复调用,并允许聚合物的内置事件系统负责更新和通知其他元素。函数:_createNewItem()用于创建对象。这简化了处理项目对象创建的位置。

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

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

我已经对您的原始代码进行了评论,说明为什么每条线应该或不应该存在。这包括更改_dataChanged

的原因

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