0

I created a custom element called <us-map-select> and want to use it twice in my app. Like so:

<us-map-select></us-map-select>
<us-map-select></us-map-select>

When I use it once (as follows), it works.

<us-map-select></us-map-select>

But when I use it twice (as follows), the app breaks and I see a blank page.

<us-map-select></us-map-select>
<us-map-select></us-map-select>

I think it might have something to do with some of the following lines in my code that might be conflicting when multiple instances are in play. The potentially problematic lines are as follows...

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
...
google.charts.setOnLoadCallback(this._drawRegionsMap.bind(this));

The full code can be seen in this jsBin (and below):

Question

Can anyone tell me what might be causing the second simultaneous instance of my element to "break" my app?

http://jsbin.com/gihezatigo/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="iron-selector/iron-selector.html" rel="import">

  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
  <script type="text/javascript" src="https://www.google.com/jsapi"></script>

</head>

<body>

  <dom-module id="x-element">

    <template>
      <style>
        #geochart {
          width: 100%;
          max-height: 500px;
        }
      </style>
      <button on-tap="_show">Show</button>
      <button on-tap="clearAll">Clear All</button>
      <button on-tap="selectAll">Select All</button>
      <div id="geochart"></div>
      <div hidden id="selectMirror">
        <iron-selector id="selector" activate-event="" selected-values="{{selectedStates}}" multi attr-for-selected="name">
          <template is="dom-repeat" items="[[items]]">
            <span name="[[item.0]]"></span>
          </template>
        </iron-selector>
      </div>
    </template>

    <script>
      (function(){
        Polymer({
          is: 'x-element',
          properties: {
            items: {
              type: Array,
              notify: true,
              value: function() {
                return [['State', 'Select'], ['Alabama', 0], ['Alaska', 0], ['Arkansas', 0], ['Arizona', 0], ['California', 0], ['Colorado', 0], ['Connecticut', 0], ['Delaware', 0], ['Florida', 0], ['Georgia', 0], ['Hawaii', 0], ['Iowa', 0], ['Idaho', 0], ['Illinois', 0], ['Indiana', 0], ['Kansas', 0], ['Kentucky', 0], ['Louisiana', 0], ['Massachusetts', 0], ['Maryland', 0], ['Maine', 0], ['Michigan', 0], ['Minnesota', 0], ['Missouri', 0], ['Mississippi', 0], ['Montana', 0], ['North Carolina', 0], ['North Dakota', 0], ['Nebraska', 0], ['New Hampshire', 0], ['New Jersey', 0], ['New Mexico', 0], ['Nevada', 0], ['New York', 0], ['Ohio', 0], ['Oklahoma', 0], ['Oregon', 0], ['Pennsylvania', 0], ['Rhode Island', 0], ['South Carolina', 0], ['South Dakota', 0], ['Tennessee', 0], ['Texas', 0], ['Utah', 0], ['Virginia', 0], ['Vermont', 0], ['Washington', 0], ['Wisconsin', 0], ['West Virginia', 0], ['Wyoming', 0]];
              }
            },
            options: {
              type: Object,
              notify: true,
              value: {
                region: 'US',
                displayMode: 'regions',
                resolution: 'provinces',
                legend: 'none',
              }
            },
            chart: {
              type: Object,
              notify: true,
              //computed: '_computeChart()',
            },
            selectedStates: {
              type: Array,
              notify: true,
              reflectToAttribute: true,
              value: function () {
                return [];
              }
            },
          },

          observers: [
            '_selectedChanged(selectedStates.*)'
          ],

          _selectedChanged: function () {
            this.items.forEach(function (stateItem, index) {
              if (!index) return;
              this.set('items.' + index + '.1', 0);
            }.bind(this));
            this.selectedStates.forEach(function (selectedState) {
              var index = null;
              this.items.some(function (state, stateIndex) {
                if (state[0] === selectedState) {
                  index = stateIndex;
                  return true;
                }
                return false;
              });
              this.set('items.' + index + '.1', 1);
            }.bind(this));

            this.selectedStates.sort();

            if (google.visualization && this._renderMap) {
              this._drawRegionsMap();
            } else {
              this._renderMap = true;
            }
          },

          _computeChart: function() {
            var out = new google.visualization.GeoChart(this.$.geochart);
            google.visualization.events.addListener(out, 'select', this._selectHandler.bind(this));
            return out;
          },

          get data() {
            return google.visualization.arrayToDataTable(this.items);
          },

          ready: function(){
            google.charts.load('current', {
              'packages': ['geochart']
            });
            google.charts.setOnLoadCallback(this._drawRegionsMap.bind(this));

          },

          clearAll: function() {
            this.set('selectedStates', []);
          },

          selectAll: function() {
            var ar = [],
                a = this.items,
                i = a.length;
            while(i---1){
              ar.push(a[i][0]);
            }
            ar.sort();
            this.set('selectedStates', ar);
          },

          _drawRegionsMap: function() {
            this.set('chart', this._computeChart());
            this.chart.draw(this.data, this.options);
          },
          _selectHandler: function() {
            var selectedItem = this.chart.getSelection();
            var row = selectedItem[0].row;
            var value = this.data.getValue(row, 0);
            this._renderMap = false;
            this.$.selector.select(value);
          },
          _show: function() {
            //console.log(this.items);
            //console.log(this.data);
            //console.log(this.chart);
            console.log(this.selectedStates);
          },
        });
      })();
    </script>

  </dom-module>

  <x-element selected-states='["Ohio"]'></x-element>

</body>
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
  • It's probably because you're including the scripts twice, I think creating an html with only the script tags and import it on your element definition might solve your problem – Alan Dávalos Feb 05 '16 at 22:31

2 Answers2

3

You are not allowed to call google.charts.load more than once. A crude solution would be to create a closure-variable as a flag to synchronize the loading state of the charts api.

So, at the top where you already have a closure:

  (function(){
    var chartStatus = '';

Then add _syncChartApi method to take care of managing the state.

      ready: function(){
        this._syncChartApi();
      },

      _syncChartApi: function() {
        switch (chartStatus) {
          case '':
            chartStatus = 'loading'
            google.charts.load('current', {
              'packages': ['geochart']
            });
          case 'loading':
            google.charts.setOnLoadCallback(function() {
              chartStatus = 'loaded';
              this._drawRegionsMap();
            }.bind(this));
            break;
          case 'loaded':
            this._drawRegionsMap();
            break;
        }
      },

http://jsbin.com/pibepis/7/edit?html,output

I provide the above mostly for educational value. :)

As @Tjwato says, you should look into the official google-chart implementation as it has more sophisticated synchronization.

Scott Miles
  • 11,025
  • 27
  • 32
1

From what I can tell the Google chart API does not like to have two instances of itself running simultaneously. Similar Problem.

May I suggest looking into google-chart element. As from what I can tell it does everything you are looking for. Hopefully this helps.

Community
  • 1
  • 1
Tjwato
  • 31
  • 4