【发布时间】:2016-02-21 07:55:22
【问题描述】:
目标
我想将selected 属性in this element 数据绑定到DOM(<div>[[selected]]</div>)。
选择一个州(如“德克萨斯”)后,我希望该州的名称出现在左上角的“科罗拉多州,南达科他州”的预选州旁边(在<div>[[selected]]</div> 标签内)。但相反,它没有。
问题
这里发生了什么?如何成功地将 DOM 数据绑定到 selected 属性?并且随着每个被选中和取消选中的新状态自动更新 DOM。
重现问题
按照以下步骤操作:
- Open this jsBin。
- 注意预选的州是科罗拉多州和南达科他州。
- 注意科拉拉多和南达科他州列在左上角。
- 点击德克萨斯。
- 观察图表中选择了德克萨斯州。
- ❌ 请注意,德克萨斯州不包括左上角的选定州列表中。即
<div>[[selected]]</div> - 单击标有“显示值”的按钮并在控制台中观察到“Texas”包含在
selected数组中。
尝试使用 .slice() 的解决方案崩溃
This SO answer explains why mutated arrays are not directly observable by the Polymer object。
@ScottMiles 写道:...您正在从事 Polymer 看不到的工作(即数组操作),然后要求
set弄清楚发生了什么。但是,当您调用this.set('selected', selected);时,Polymer 会看到selected的身份没有改变(也就是说,它与之前的 Array 对象相同)并且它只是停止处理。
所以我尝试通过在原始数组上使用.slice() 方法创建一个新数组来解决问题,如下所示。
// Sort new 'selected' array
_selectedChanged: function(selectedInfo) {
var selected = this.selected.slice();
selected.sort();
//this.set('selected', selected); // Uncommenting this line crashes call stack
},
这似乎解决了可观察性问题,但会产生副作用问题并使调用堆栈崩溃。
来源
http://jsbin.com/yosajuwime/1/edit?html,控制台,输出<!DOCTYPE html>
<head>
<meta charset="utf-8">
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link href="google-chart/google-chart.html" rel="import"> </head>
<body>
<dom-module id="x-element"> <template>
<style>
google-chart {
width: 100%;
}
</style>
<br><br><br><br>
<button on-tap="_show">Show Values</button>
<button on-tap="clearAll">Clear All</button>
<button on-tap="selectAll">Select All</button>
<div>[[selected]]</div>
<google-chart id="geochart"
type="geo"
options="[[options]]"
data="[[data]]"
on-google-chart-select="_onGoogleChartSelect">
</google-chart>
</template>
<script>
(function() {
// google-chart monkey patch
var gcp = Object.getPrototypeOf(document.createElement('google-chart'));
gcp.drawChart = function() {
if (this._canDraw) {
if (!this.options) {
this.options = {};
}
if (!this._chartObject) {
var chartClass = this._chartTypes[this.type];
if (chartClass) {
this._chartObject = new chartClass(this.$.chartdiv);
google.visualization.events.addOneTimeListener(this._chartObject,
'ready', function() {
this.fire('google-chart-render');
}.bind(this));
google.visualization.events.addListener(this._chartObject,
'select', function() {
this.selection = this._chartObject.getSelection();
this.fire('google-chart-select', { selection: this.selection });
}.bind(this));
if (this._chartObject.setSelection){
this._chartObject.setSelection(this.selection);
}
}
}
if (this._chartObject) {
this._chartObject.draw(this._dataTable, this.options);
} else {
this.$.chartdiv.innerHTML = 'Undefined chart type';
}
}
};
Polymer({
is: 'x-element',
/** /
* Fired when user selects chart item.
*
* @event us-map-select
* @param {object} detail Alpabetized array of selected state names.
/**/
properties: {
items: {
type: Array,
value: function() {
return [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming', ].sort();
},
},
color: {
type: String,
value: 'blue',
},
options: {
type: Object,
computed: '_computeOptions(color)',
},
selected: {
type: Array,
value: function() {
return [];
}
},
data: {
type: Array,
computed: '_computeData(items, selected.length)'
},
},
observers: [
'_selectedChanged(selected.length)',
],
_computeOptions: function() {
return {
region: 'US',
displayMode: 'regions',
resolution: 'provinces',
legend: 'none',
defaultColor: 'white',
colorAxis: {
colors: ['#E0E0E0', this.color],
minValue: 0,
maxValue: 1,
}
}
},
// On select event, compute 'selected'
_onGoogleChartSelect: function(e) {
var string = e.path[0].textContent.split('Select')[0].trim(), // e.g. 'Ohio'
selected = this.selected, // Array of selected items
index = selected.indexOf(string);
// If 'string' is not in 'selected' array, add it; else delete it
if (index === -1) {
this.push('selected', string);
} else {
this.splice('selected', index, 1);
}
},
// Sort new 'selected' array
_selectedChanged: function(selectedInfo) {
var selected = this.selected.slice();
selected.sort();
//this.set('selected', selected); // Uncommenting this line crashes call stack
},
// After 'items' populates or 'selected' changes, compute 'data'
_computeData: function(items, selectedInfo) {
var data = [],
selected = this.selected,
i = items.length;
while (i--) {
data.unshift([items[i], selected.indexOf(items[i]) > -1 ? 1 : 0]);
}
data.unshift(['State', 'Select']);
return data;
},
clearAll: function() {
this.set('selected', []);
},
selectAll: function() {
this.set('selected', this.items);
},
_show: function() {
//console.log('items', this.items);
console.log('selected', this.selected);
//console.log('data', this.data);
},
});
})();
</script>
</dom-module>
<x-element color="red" selected='["Colorado", "South Dakota"]'></x-element>
</body>
</html>
【问题讨论】:
-
您的
setcraster calls call stack,因为您有效地说:“当所选数组更改时,更改选定的数组”,这是一个无限循环。 Fwiw,您的绑定以计算已排序的连接字符串的解决方案是一个很好的解决方案,因为您的输出相对简单。 -
I wrote this demo 查看外部元素是否存在任何问题,通过数据绑定观察数组属性的更改,而无需采取任何其他步骤。显然,当观察者是外部元素时,一切正常......plnkr.co/edit/NBsxZLkfg5fxFEXW06H9?p=preview
标签: javascript data-binding polymer polymer-1.0