javascript - polymer 1.x : Pre-load element attributes

标签 javascript data-binding polymer polymer-1.0

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

<小时/>

我的目标

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

预期行为与实际行为

我希望看到页面加载一张包含美国所有州轮廓的 map 。控制台中没有错误。科罗拉多州和南达科他州已预先选定并涂成蓝色。

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

控制台错误

TypeError: Cannot read property 'length' of undefined

可能出现的问题及解决方案

问题是items属性尚未由 ready 填充_doAll之前的函数尝试访问它以设置选定的状态。

我将问题跟踪到代码中的以下位置:

http://jsbin.com/qezogimude/1/edit?html,控制台,输出
_doAll: function(verb) {
  ...
  var items = this.items, // undefined
      i = items.length; // error, crashes
  ...

我还(未成功)尝试了以下操作(单独):

  • async
  • while(this.items === undefined){...

重现问题

以下步骤将重现该问题:

  1. Open this jsBin .
  2. 请注意, map 已正确加载到输出 Pane 中。 (并且在选择和取消选择状态时正常工作。)
  3. 向下滚动到页面底部到 <x-element>标签。
  4. 删除 x selected 前面的字符属性,因此完整的属性为:selected='["Colorado", "South Dakota"]' .
  5. 请注意, map 消失了,不再正确加载,并且控制台中出现上述错误。
  6. 替换x您刚刚删除并注意到 map 加载并再次正常工作。

问题

如何获取_doAll等待ready填充items属性(property)?如果可以的话,请提供您的解决方案的有效 jsBin 示例。

http://jsbin.com/qezogimude/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%;
          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>

最佳答案

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

您还没有使项目可观察 - 那么它是如何变化的以及当它变化时您如何重新计算?

我不确定 doAll 正在尝试做什么,但您可能需要进行一些检查以确保项目是否有效,因为它在创建项目时以某种方式调用。

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

关于javascript - polymer 1.x : Pre-load element attributes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35288262/

相关文章:

css - Polymer 1.0 我如何设计纸张输入 :disabled?

javascript - 无法从 jquery 的表单中获取输入值

javascript - 如何让 Google Analytics 在单页应用程序中显示正确的页面标题?

javascript - 使用Fetch API,处理错误时如何访问JSON数据

c# - 如何让 BindingSource 知道其 DataSource 的变化?

java - 在 Springs Velocity 绑定(bind)宏(或 JSP 标记库)中,对 "command"的引用是什么?

silverlight - 将 Silverlight UserControl 自定义属性绑定(bind)到其元素

javascript - slim -通过常规 Prop 传递使用上下文API(setContext/getContext)

javascript - 在 Chrome 中点击时 polymer 纸对话框不显示

polymer - “polymer ”未被识别为内部或外部命令