注意:这个问题是is not a duplicate of this SO question,因为第一个问题是通过标记中的语法修正来解决的。此问题涉及JavaScript并且有不同的错误消息。
我正在尝试通过声明属性将名为selected
的自定义元素属性预设为值["Colorado", "South Dakota"]
。
我希望看到该页面加载一张包含所有美国州大纲的地图。控制台中没有错误。科罗拉多州和南达科他州预选并涂上了蓝色。
相反,我看到一个没有地图的空白页面。该页面打印出正确的selected
变量:Colorado,South Dakota
。控制台中的一组错误从以下内容开始:
TypeError: Cannot read property 'length' of undefined
问题是items
函数在ready
尝试访问它以设置所选状态之前尚未填充_doAll
属性。
我将问题跟踪到代码中的以下位置:
http://jsbin.com/qezogimude/1/edit?html,console,output_doAll: function(verb) {
...
var items = this.items, // undefined
i = items.length; // error, crashes
...
我也(不成功)尝试了以下(单独):
async
while(this.items === undefined){...
以下步骤将重新创建问题:
<x-element>
标记。x
属性前面的selected
字符,以便完整属性显示为:selected='["Colorado", "South Dakota"]'
。x
,注意地图加载并再次正常工作。如何让_doAll
等待ready
填充items
属性?如果可以,请提供解决方案的有效jsBin示例。
<!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%;
max-height: 300px;
}
</style>
<button on-tap="_show">Show</button>
<div>[[selected]]</div>
<google-chart
id="geochart"
type="geo"
options="{{options}}"
data="{{items}}"
xon-google-chart-select="_onGoogleChartSelect"></google-chart>
</template>
<script>
(function(){
Polymer({
is: 'x-element',
/** /
* Fired when user selects chart item.
*
* @event us-map-select
* @param {object} detail Alpabetized array of selected state names.
/**/
properties: {
selected: {
type: Array,
notify: true,
//reflectToAttribute: true,
},
items: {
type: Array,
notify: true,
reflectToAttribute: true,
},
color: {
type: String, // '#455A64'
value: function() {
return 'blue';
}
},
options: {
type: Object,
notify: true,
reflectToAttribute: true,
computed: '_computeOptions(color)'
},
itemIndices: {
type: Object,
computed: '_computeItemIndices(items)',
},
},
observers: [
'_selectedChanged(selected.*)'
],
ready: function() {
var a = [['State', 'Select'], ['Alabama', 0], ['Alaska', 0], ['Arizona', 0], ['Arkansas', 0], ['California', 0], ['Colorado', 0], ['Connecticut', 0], ['Delaware', 0], ['Florida', 0], ['Georgia', 0], ['Hawaii', 0], ['Idaho', 0], ['Illinois', 0], ['Indiana', 0], ['Iowa', 0], ['Kansas', 0], ['Kentucky', 0], ['Louisiana', 0], ['Maine', 0], ['Maryland', 0], ['Massachusetts', 0], ['Michigan', 0], ['Minnesota', 0], ['Mississippi', 0], ['Missouri', 0], ['Montana', 0], ['Nebraska', 0], ['Nevada', 0], ['New Hampshire', 0], ['New Jersey', 0], ['New Mexico', 0], ['New York', 0], ['North Carolina', 0], ['North Dakota', 0], ['Ohio', 0], ['Oklahoma', 0], ['Oregon', 0], ['Pennsylvania', 0], ['Rhode Island', 0], ['South Carolina', 0], ['South Dakota', 0], ['Tennessee', 0], ['Texas', 0], ['Utah', 0], ['Vermont', 0], ['Virginia', 0], ['Washington', 0], ['West Virginia', 0], ['Wisconsin', 0], ['Wyoming', 0]];
this.set('items', a);
var _this = this;
this.$.geochart.addEventListener('google-chart-select', function(e){this._onGoogleChartSelect(e)}.bind(_this));
},
_computeItemIndices: function(a) {
var out = {},
i = a.length;
while(i--){
out[a[i][0]] = i;
}
return out;
},
_onGoogleChartSelect: function(e) {
var s = e.path[0].textContent.split('Select')[0].trim(), // e.g. 'Ohio'
temp = [],
a = this.items,
index = this.itemIndices[s], // e.g. 35
i = a.length;
this.set('items.' + index + '.1', a[index][1] ? 0 : 1);
while(i---1){
/** /
if(s === a[i][0]){
this.set('items.' + i + '.1', a[i][1] ? 0 : 1);
//this.items[i][1] = a[i][1] ? 0 : 1;
}
/**/
if(a[i][1]){
temp.push(a[i][0]);
}
}
temp.sort();
this.set('selected', temp);
this._drawChart();
//console.log(this.selected);
},
_drawChart: function() {
this.$.geochart._dataTable=this.$.geochart._createDataTable(this.items);
this.$.geochart._chartObject.draw(this.$.geochart._dataTable,
this.$.geochart.options);
},
doAll: function(verb) {
verb = verb || 'clear'; // verb: 'clear'(default)|'select'
verb = (verb === 'select') ? 'select' : 'clear';
this._doAll(verb);
this._drawChart();
},
_doAll: function(verb) {
var resetSelect = (verb && verb === 'some') ? false : true;
verb = verb || 'clear'; // verb: 'clear'(default)|'select'|'some'
verb = (verb === 'select') ? 'select' : 'clear';
var temp = [];
var items = this.items, // undefined
i = items.length; // error, crashes
switch(verb) {
case 'select':
while(i---1){
items[i][1] = 1;
temp.push(items[i][0]);
}
break;
case 'clear':
while(i---1){
items[i][1] = 0;
}
break;
default:
break;
}
this.set('items', items);
if(resetSelect){
temp.sort();
this.set('selected', temp);
}
},
_selectedChanged: function(e) {
var a = e.base,
i = a.length;
this._doAll('some');
while(i--){
var index = this.itemIndices[a[i]];
this.set('items.' + index + '.1', 1);
}
this._drawChart();
this.fire('us-map-select', this.selected)
console.log(this.selected);
},
_computeOptions: function(str) {
return {
region: 'US',
displayMode: 'regions',
resolution: 'provinces',
legend: 'none',
defaultColor: '#F5F5F5',
colorAxis: {
colors: ['#F5F5F5', str],
minValue: 0,
maxValue: 1,
}
}
},
_show: function(){
//this.set('selected', ['Ohio', 'New Mexico']);
this.doAll();
//console.log(this.itemIndices);
},
});
})();
</script>
</dom-module>
<x-element xcolor="#455A64"
xselected='["Colorado", "South Dakota"]'></x-element>
</body>
</html>
答案 0 :(得分:2)
查看您的jsbin,问题是您的商品属性没有默认值。我尝试将其设置为[],但是你的_doAll函数试图访问它的第一个元素。
你还没有观察到物品 - 所以它是如何变化的,你怎么重新计算呢?
我不确定doAll会尝试做什么,但是您可能想要对项目进行一些检查,因为在项目创建时它会被调用。
我有类似的东西,发现最好的方法是从它作为计算属性派生属性,然后我用它来通过数据绑定来驱动我的元素。这样,所有作为项目被创建并且在其中具有错误值的边缘情况都消失了。