PolymerElements / iron-list

Element for a virtual, "infinite" list
https://www.webcomponents.org/element/PolymerElements/iron-list
217 stars 131 forks source link

Large spaces between list items while loading when switching from grid to list view. #248

Open liechtym opened 8 years ago

liechtym commented 8 years ago

Description

I am working in a gallery app where we have a 'grid' view and a 'list' view. We used iron-list for both of these views...both use the same iron-list element to display, we just switch between grid='true' and grid='false' to switch from view to view and use a dom-if to switch between grid-items and list items.

I noticed that when we load the gallery in grid view (grid='true') and switch to list view, I initially see large spaces between list elements for about 2 seconds, and then the view snaps to its intended styling (no margin or padding between items). It typically does this longer depending on the number of list/grid items. For example, if there's 1-70 items, it's just a flicker. With 100+ items, it can be 1 to 5 seconds. Our QA found that on some devices like the iPad, it can be 10 seconds to an indefinite amount of time. Here's screenshots of each step in replicating the issue.

Expected outcome

Grid view (grid='true') switches to list view (grid='false') smoothly without the list view having a bunch of extra space between items. Alternatively, iron-list could fire an event when it is done rendering so I can put a spinner screen on the list-view while it renders.

Actual outcome

Large spaces between items when switching from grid to list view on initial render, mostly when there are 100+ items in the list

Screenshots

Step 1: https://drive.google.com/open?id=0B5Rdg01TIwkHQnFJR3hfeGRvNDg

Step 2: https://drive.google.com/open?id=0B5Rdg01TIwkHMndmVmlJMGxES28

Step 3: https://drive.google.com/open?id=0B5Rdg01TIwkHWXdiR25nWmV1dWc

Steps to reproduce

  1. Create an iron-list element with several items
  2. Switch from grid='true' to grid='false'

    Browsers Affected

    • [X] Chrome
    • [X] Firefox
    • [X] Safari 9
    • [x] IPad Safari
    • [X] Android Chrome
    • [?] Safari 8
    • [?] Safari 7
    • [?] Edge
    • [? ] IE 11
    • [?] IE 10
Westbrook commented 8 years ago

Two questions:

  1. How are you triggering the layout update after you set grid = false? My code doesn't seem to hot swap and requires a notifyResize() before it applies the new layout without any spacing issues.
  2. Are you sure you've appropriately set the size of your iron-list? The idea that the processing takes longer as you have more elements makes me believe that height isn't being manages correctly and there are DOM nodes being created for every element in your list rather than only those that are visible.
liechtym commented 8 years ago

Here's two answers:

  1. I am using this.fire('iron-resize') in an observer on the parent element's property that sets the grid property on iron-list. This is what makes it end up in the correct view (see Step 3 on screenshots).
  2. If I am correct, the parent container of iron-list must be a fixed height and width. Currently, I have it in a paper-scroll-header-panel with class='fit'. According to the documentation I've read, this should work? But I think you're right that an element is getting created for every list item. I see them all being created in my web inspector. Not sure why this would happen? Maybe I'm missing something?
blasten commented 8 years ago

I see, I think the list should handle this use case a little better for you. It seems like there's async work waiting to complete. Can you try: Polymer.dom.flush() right after you changed the grid property?

liechtym commented 8 years ago

@blasten On reading your comment, I put Polymer.dom.flush() in the observer for the parent element's property and didn't see any change.

liechtym commented 8 years ago

After sending the last message, I realized you probably meant the Polymer.dom.flush() should be run after the iron-resize. I did this and am now no longer seeing the spacing issue between the items. It does, however, now take 4 or 5 seconds to change to list view. Around 70 elements are rendering at a time which seems large (there are 168 overall). Is there anything I can do to reduce this number?

liechtym commented 8 years ago

Interesting. When I start in list view, only 27 item elements are rendered. If I switch to grid view, then there are 70. However, when I start in grid view there are 70, but when I switch to list view, there are 168, the total number of list items! No wonder it is rendering so slowly!

blasten commented 8 years ago

Yeah the Polymer.dom.flush() needs to run after firing iron-resize. I'm not sure why it's so slow though, can you still repro the same issue without Polymer.dom.flush()?

liechtym commented 8 years ago

Yes, without the Polymer.dom.flush() I still got 168 'item' elements rendering when initially loading in grid view (where there were 70 elements loaded), then switching to list view (where 168 were loading). Again, loading list view directly only gave me 43 'item' elements and had much better performance.

blasten commented 8 years ago

It seems like the element that handles scroll events needs a size. Did you set a height to the <iron-list> element? If you are using a custom scroll target, that target must be sized.

Important: iron-list must either be explicitly sized, or delegate scrolling to an explicitly sized parent. By "explicitly sized", we mean it either has an explicit CSS height property set via a class or inline style, or else is sized by other layout means (e.g. the flex or fit classes).