Search code examples
javascriptdompolymerweb-component

Run a method once dom-repeat's rendering is all done


I have a dom-repeat element displaying records, and would like to run an operation once dom-repeat is finished. This is so that I can run:

    this.$.content.scrollTop = this.$.content.scrollHeight;

(It's a chat system, it would be silly not to scroll down to the last one).

It's a fairly normal dom-repeat template... I tried plugging myself as a filter for it, or observing the data, but in all cases I get called before rendering has happened.

Here is the dom-repeat -- how do I do this?

    <div class="content" id="content">
      <div class="container-fluid">
        <template is="dom-if" if="[[!_dataThere(data)]]">
          <my-empty-list icon="question-answer" message="You haven't talk to this user yet. (You can do it now!)"></my-empty-list>
        </template>

        <hot-network manage-errors>
          <iron-ajax id="aj" auto url="{{_makeUrl(userId,userData.generic.id)}}" handle-as="json" last-response="{{data}}"></iron-ajax>
          <template is="dom-if" if="[[_dataThere(data)]]">

            <template is="dom-repeat" items="[[data]]">

              <div class$="message {{_theirsOrMine(item)}}">
                <div class="message-inner">
                  <div class="avatar"></div>
                  <div class="bubble">{{ item.message}}</div>
                </div>
                <div class="meta">{{_formattedDate(item.added)}}</div>
              </div>

            </template>

          </template>
        </hot-network>
      </div>
    </div>

Solution

  • To register a one-time callback after the next render, use Polymer.RenderStatus.afterNextRender(this, function() {...}), where this is your Polymer object.

    Example:

    Polymer({
      _addItem: function() {
        this.push('items', new Item());
        Polymer.RenderStatus.afterNextRender(this, () => {
          // set scroll top
        });
      }
    });
    

    codepen

    The method is currently undocumented in 1.x (even in its source code), but you'll notice it in the 2.0 upgrade guide in Callbacks contracts have changed:

    Use the Polymer.RenderStatus.afterNextRender function to register a one-time callback after the next render.

    I first discovered it at Google I/O 2016 Practical lessons from a year of building web components.