How to set scroll-target on an iron-list within an app-header-layout with has-scrolling-region
Asked Answered
S

3

5

I am trying to use an iron-list (and iron-scroll-threshold) within a app-header-layout with has-scrolling-region.

I generated the basic app layout with the polymer-CLI.

If I do not use has-scrolling-region on the app-header-layout and use "document" for scroll-target on the iron-list it kinda works. But with this solution the scrollbar belongs to the window and does not slide beneath the header and I obviously cannot get the nice "waterfall" behaviour that is usually associated with these kinds of layouts.

Therefore, I use has-scrolling-region on the app-header-layout, but what is the right way to pass the corresponding scoller to the scroll-target property of the iron-list?

  <!-- Main content -->
  <app-header-layout has-scrolling-region id="layout">
    <app-header condenses reveals effects="waterfall">
      <app-toolbar>
        <paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
        <div title>Twiamo</div>
      </app-toolbar>
    </app-header>

    <iron-pages role="main" selected="[[page]]" attr-for-selected="name" id="page">
      <my-iron-list name="view1" scroll-target="[[_getScrollTarget()]]"></my-iron-list>
      <my-view2 name="view2"></my-view2>
      <my-view3 name="view3"></my-view3>
    </iron-pages>
  </app-header-layout>

I looked into the implementation of app-header-layout to find the right element. This expression actually yields me the right element and everything works fine.

_getScrollTarget: function() {
    return this.$.layout.shadowRoot.querySelector("#contentContainer");        
}

But there has to be a better, a right way? Grabbing into the shadow DOM of the app-header-layout is not exactly using "public interface"!

To complete the example, here my code for my-iron-list. My-iron-list wraps and iron-list, iron-scroll-theshold, and some dummy data provider stuff. The scroll-target on my-iron-list is just passed to the iron-list and iron-scroll-threshold within my-iron-list:

<dom-module id="my-iron-list">
  <template>
    <iron-list items="[]" as=item id="list" scroll-target="[[scrollTarget]]">
      <template>
        <div class="item">[[item]]</div>
      </template>
    </iron-list>

    <iron-scroll-threshold
        id="scrollTheshold"
        lower-threshold="100"
        on-lower-threshold="_loadMoreData"
        scroll-target="[[scrollTarget]]">      
    </iron-scroll-threshold>    
  </template>

  <script>
    Polymer({

      is: 'my-iron-list',

      properties: {
        page: {
            type : Number,
            value : 0
        },
        perPage: {
            type : Number,
            value : 100
        },
        scrollTarget: HTMLElement,
      },

      _pushPage: function() {
          for (i = 0; i < this.perPage; i++) {
            this.$.list.push('items', 'Entry number ' + (i+1+this.page*this.perPage));   
          }
      },

      _loadMoreData: function() {
          this._pushPage();
          this.page = this.page + 1;
          this.$.scrollTheshold.clearTriggers();
      }
    });
  </script>
</dom-module>
Secundines answered 31/5, 2016 at 11:36 Comment(0)
A
4

I have the same problem as you, for now the cleanest anwser I have was to use the app-header scrollTarget.

In your case move add an id to the app-header

 <app-header condenses reveals effects="waterfall" id="header">
      <app-toolbar>
        <paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
        <div title>Twiamo</div>
      </app-toolbar>
 </app-header>

and then instead of

_getScrollTarget: function() {
    return this.$.layout.shadowRoot.querySelector("#contentContainer");        
}

just use the scrollTarget property

_getScrollTarget: function() {
    return this.$.header.scrollTarget;     
}

If you found out a better way let me know.

Cheers,

Antinucleon answered 7/6, 2016 at 17:2 Comment(1)
This looks pretty much like the right solution, and I tried that before. For some reason it does not do the trick for me. I probably build something weird that somehow obstructs the right flow of events. But good to know that is should work in principle.Secundines
J
4

I struggled with the same issue. While I was using iron-scroll-target-behavior instead of iron-scroll-threshold, I still needed to pass a scroll-target reference to an element inside a app-layout-header.

If has-scrolling-region is true, app-header-layout sets the scroll-target to be an internal div with an ID of #contentContainer. You can target this div and pass it as the scroll-target to your iron-list.

You would just need to alter the _getScrollTarget function inside your original code.

_getScrollTarget: function() {
    return this.$.layout.$.contentContainer;     
}

Hope it helps!

Jab answered 9/2, 2017 at 19:46 Comment(0)
P
4

If anyone is coming here for an answer in 2017, I'm just letting you know that the same issue persists in Polymer 2.0.

I was able to overcome the issue by having the following code in my app shell (eg. PSK's my-app.html):

First, put an id attribute of 'layout' on your app-header-layout element.

Next, add this to your Polymer class (in your my-app.html equivalent):

static get properties() {
  return {
    scrollTarget: HTMLElement,
  }
}

ready() {
  super.ready();
  this.scrollTarget = this.$.layout.shadowRoot.querySelector("#contentContainer");
}

Then, pass in the property to a scroll-target attribute on your lazy-loaded pages:

<my-page scroll-target="[[scrollTarget]]"></my-page>

Finally, in your lazy-loaded pages (eg. my-page):

<iron-list scroll-target="[[scrollTarget]]"></iron-list>

...

static get properties() {
  return {
    scrollTarget: HTMLElement,
  }
}

This isn't an ideal solution, but it works.

Pushover answered 9/8, 2017 at 17:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.