Polymer 1.x:预加载元素属性

时间:2016-02-09 09:29:21

标签: javascript data-binding polymer polymer-1.0

注意:这个问题是is not a duplicate of this SO question,因为第一个问题是通过标记中的语法修正来解决的。此问题涉及JavaScript并且有不同的错误消息。

我的目标

我正在尝试通过声明属性将名为selected的自定义元素属性预设为值["Colorado", "South Dakota"]

预期与实际行为

我希望看到该页面加载一张包含所有美国州大纲的地图。控制台中没有错误。科罗拉多州和南达科他州预选并涂上了蓝色。

相反,我看到一个没有地图的空白页面。该页面打印出正确的selected变量:Colorado,South Dakota。控制台中的一组错误从以下内容开始:

console.error
  

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){...

重新创建问题

以下步骤将重新创建问题:

  1. Open this jsBin
  2. 请注意,地图会在输出窗格中正确加载。 (当选择和取消选择状态时,它可以正常工作。)
  3. 向下滚动到页面底部的<x-element>标记。
  4. 删除x属性前面的selected字符,以便完整属性显示为:selected='["Colorado", "South Dakota"]'
  5. 请注意,地图已消失,无法再正确加载,并且上述错误会显示在控制台中。
  6. 替换刚删除的x,注意地图加载并再次正常工作。
  7. 问题

    如何让_doAll等待ready填充items属性?如果可以,请提供解决方案的有效jsBin示例。

    http://jsbin.com/qezogimude/1/edit?html,console,output
    <!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>
    

1 个答案:

答案 0 :(得分:2)

查看您的jsbin,问题是您的商品属性没有默认值。我尝试将其设置为[],但是你的_doAll函数试图访问它的第一个元素。

你还没有观察到物品 - 所以它是如何变化的,你怎么重新计算呢?

我不确定doAll会尝试做什么,但是您可能想要对项目进行一些检查,因为在项目创建时它会被调用。

我有类似的东西,发现最好的方法是从它作为计算属性派生属性,然后我用它来通过数据绑定来驱动我的元素。这样,所有作为项目被创建并且在其中具有错误值的边缘情况都消失了。