简体   繁体   中英

Polymer :: Unable to target elements inside dom-repeat when using iron-ajax to import data

I can target element inside dom-repeat if the data is hard-coded as a property value. However, when using iron-ajax to import the data, this.$$(selector) returns null .

Custom Element

<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-collapse/iron-collapse.html"/>
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html"/>
<link rel="import" href="../../bower_components/polymer-sortablejs/polymer-sortablejs.html"/>

<dom-module id="sortable-math">

  <template>
    <style>
      :host {
        display: block;
      }

      .math {
        display: block;
        padding: 20px 0;
        border-bottom: 1px solid #cccccc;
      }

      .total {
        border-top: 1px solid #cccccc;
      }
    </style>

    <h1>Math +</h1>

    <div id="empty-div"></div>

    <iron-ajax
        auto
        id="numbersDataRequest"
        url="../data/numbers.json"
        handle-as="json"
        on-response="numbersDataResponse">
    </iron-ajax>

    <div>
      <sortable-js>
        <template is="dom-repeat" items="{{numbersData}}">
          <div id="math-{{index}}" class="math">
            <table>
              <tr>
                <td class="givenNumber" on-click="toggle" toggle-id$="{{index}}">
                  {{item.givenNumber}}
                </td>
              </tr>
              <tr>
                <td class="toAdd">
                  + {{item.toAdd}}
                </td>
              </tr>
              <tr>
                <td id="total-{{index}}" class="total">?</td>
                <td></td>
              </tr>
            </table>

            <iron-collapse id$="collapsible-{{index}}">
              <div>Hint</div>
            </iron-collapse>
          </div>
        </template>
      </sortable-js>

  </div>

  </template>

  <script>
    Polymer({
      is: 'sortable-math',

      properties: {
        numbersData: {
          type: Array
        }
      },

      ready: function() {
        console.log(this.$$('#empty-div'));
      },

      _onSort: function(evt){
        console.log('sorted');
      },

      /*
      //Not working either

      attached: function(){
        this.async(function() {
          this.$$('#empty-div').innerHTML = 'Empty no more.'; //This works.
          console.log(this.$$('#math-1')); //Returns null
        });
      },

      */

      toggle: function (e, detail, sender) {
        var target = Polymer.dom(e).rootTarget.getAttribute('toggle-id'),
            selector = '#collapsible-' + target;
        this.$$(selector).toggle();
        console.log(this.$$('#math-1')); 
      },

      numbersDataResponse: function (data) {
        //console.log('numbersDataResponse');
        this.numbersData = data.detail.response;
        this.$$('#empty-div').innerHTML = 'Empty no more.'; //This works.

        //Attempt to target element created with dom-repeat
        console.log(this.$$('#math-0')); //Returns null
        console.log(this.$$('#math-0 #total-0')); //Returns null
        console.log(this.$$('#math-0 .total')); //Returns null
      }
    });

    var targetEl = function(ref, selector){
      return Polymer.dom(ref).querySelector(selector);
    }



  </script>
</dom-module>

JSON

[
  {
    "givenNumber": "3",
    "toAdd": "2"
  },
  {
    "givenNumber": "?",
    "toAdd": "5"
  },
  {
    "givenNumber": "?",
    "toAdd": "10"
  },
  {
    "givenNumber": "?",
    "toAdd": "7"
  }
]

Additional info

What I am trying to do:

  1. Get content of #math-0 .givenNumber ( 3 )
  2. Get content of #math-0 .toAdd : ( 2 )
  3. Calculate the total ( 5 ) and append it to #math-1 .givenNumber
  4. Get content of #math-1 .givenNumber : ( 5 )
  5. Get content of #math-1 .toAdd : ( 5 )
  6. Calculate the total ( 10 ) and append it to #math-2 .givenNumber

and so on ...

View without calculation

  • 3 + 2 = ?
  • ? + 5 = ?
  • ? + 10 = ?
  • ? + 7 = ?

View after calculation

  • 3 + 2 = 5
  • 5 + 5 = 10
  • 10 + 10 = 20
  • 20 + 7 = 27

Thanks!

You're querying for the repeater's items before the repeater has had a chance to stamp them, which results in null . You could either wait until after the next render with Polymer.RenderStatus.afterNextRender() before querying the item:

Polymer.RenderStatus.afterNextRender(this, () => {
  console.log('math-0 (after render)', this.$$('#math-0'));
});

...or you could wait until the end of the current microtask (which includes the template repeater rendering):

this.async(() => {
  console.log('math-0 (after microtask)', this.$$('#math-0'))
});

 <head> <base href="https://polygit.org/polymer+1.7.0/polymer-sortablejs+SortableJS+:master/Sortable+RubaXa+:master/components/"> <script src="webcomponentsjs/webcomponents-lite.min.js"></script> <link rel="import" href="polymer/polymer.html"> <link rel="import" href="iron-ajax/iron-ajax.html"> <link rel="import" href="polymer-sortablejs/polymer-sortablejs.html"> </head> <body> <x-foo></x-foo> <dom-module id="x-foo"> <template> <style> :host { font-family: Roboto, sans-serif; } .item { margin: 20px; } </style> <iron-ajax url="https://jsonplaceholder.typicode.com/posts" on-response="_onResponse" auto></iron-ajax> <sortable-js> <template is="dom-repeat" items="[[items]]"> <div class="item" id$="item-{{index}}">{{item.title}}</div> </template> </sortable-js> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-foo', _onResponse: function(e) { this.items = e.detail.response; // The template repeater has not rendered its items yet, so #item-1 would // not yet exist yet for us to query here. console.log('item-1 (before render)', this.$$('#item-1')); // We can use Polymer.RenderStatus.afterNextRender to explicitly wait until // the next render event before checking for #item-1. Polymer.RenderStatus.afterNextRender(this, () => console.log('item-1 (after render)', this.$$('#item-1'))); // Alternatively, we can wait until the end of the current microtask (which // includes rendering the template repeater), before checking for #item-1. this.async(() => console.log('item-1 (after microtask)', this.$$('#item-1'))); } }); }); </script> </dom-module> </body> 

codepen

Because the dom-repeat takes time to bind, so the parameters will be set directly after the call will have time difference, it is recommended to wait and then call on it

English is not good, I hope you see understand, thank you

jsbin

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM