Ionic-framework: Ionic 2: VirtualScroll items overlapping. Poor rendering on delayed transport

Created on 7 May 2017  Â·  37Comments  Â·  Source: ionic-team/ionic-framework

Ionic version: (check one with "x")
[x] 3.x

Note: I think this is BOTH a bug AND a feature request.

I'm submitting a ... (check one with "x")
[x] bug report
[x] feature request

Current behavior:
VirtualScroll does not support items of variable height and seems to have issues rendering data that is delayed in transport.

Expected behavior:
VirtualScroll renders correctly first time.

Steps to reproduce:
http://plnkr.co/edit/etNNT8tKJB4yKMVV0F7a?p=preview

Related code:
See plunkr.

Other information:
https://forum.ionicframework.com/t/ionic-2-virtualscroll-items-overlapping-on-first-render/89230/7

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

global packages:

    @ionic/cli-utils : 1.0.0-rc.0
    Cordova CLI      : 6.5.0 
    Ionic CLI        : 3.0.0-rc.0

local packages:

    @ionic/app-scripts              : 1.3.0
    @ionic/cli-plugin-cordova       : 1.0.0-rc.0
    @ionic/cli-plugin-ionic-angular : 1.0.0-rc.0
    Ionic Framework                 : ionic-angular 3.0.1

System:

    Node       : v6.10.0
    OS         : OS X El Capitan
    Xcode      : Xcode 8.2.1 Build version 8C1002 
    ios-deploy : 1.9.1 
    ios-sim    : 5.0.8 
v3

Most helpful comment

My STRONG advice is to find a way around using virtual scroll. Make your
list filtered in some way that means you can render all the items normally.

Virtual Scroll is completely and utterly broken and not worth wasting time
on until someone from the Ionic team acknowledges the multitude of issues
surrounding it and fixes them.

But then they seem far more focused on PWA matters to bother with trivial
things like making a stable and robust framework...

Maybe if this gets enough upvotes someone will actually do something? Who
knows.

On 6 Feb 2018 12:48, "Robson Garcia" notifications@github.com wrote:

Is there any update on that issue? I have a variable height component
inside virtualItem and I have the same problem.

The workarounds provided in this thread are not working for me.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ionic-team/ionic/issues/11542#issuecomment-363411781,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ANnlXvRiMJBeA2N9n-n6SUlPEpDs0EFXks5tSEoXgaJpZM4NTIe7
.

All 37 comments

with ionic-angular 3.1.1 is still the same, although i'm using virtual scroll with different data.
The height of rows are the same. I pointed out, always the second element on every page (server paging) renders incorrectly - starting from second element, if only 3 item can fit the height of the scrolling area problem does not happen. (approxItemHeight is more than 100-150px)
Even if i tried to customize the approxItemHeight, it didn't help. (I set 50px, although my element is about 70px)

To daveshirman:
My problem occurs inside a dialog which has tabs and inside tabs has scrolling area.

Document tells you if you wrap up

<ion-list [virtualScroll]>
<div *virtualItem="let row">
<ion-item>
</ion-item>
</div>
</ion-list>

it renders correctly - the rendering is completely changed.

In my case as i'm reducing the width of the item-s on the screen to deal with bigger screens it's screwing up the whole regarding to the width, but if don't do that, worth to give a shot, as it seems to me at least the height is correct, and seems to me there is some sort of variable height support also.
At least you can play around on it. (you can find workaround for yours one)

Thanks for opening an issue with us! We are planning on making some improvements soon to virtualscroll which should improve its ability to handle items of varying height.

@jgw96 Is there a milestone for this? My app is in production and currently, my only workaround for this is to load the data twice, forcing a re-render.

Good question! So this issue https://github.com/driftyco/ionic/issues/8744 is currently on the 3.2.0 milestone, but it looks like most of the fixes are gonna have to wait until the next release after this one. As a better workaround, could you try calling this method after your data is completely loaded in?

@jgw96 I did think of that, but when I try it, I get an error:

Markup:

<ion-list #virtualScroll [virtualScroll]="finalOrderedJobsList" [headerFn]="getHeaderDate" approxItemHeight="300px">
...

Code:

export class MyJobsPage {

  @ViewChild('virtualScroll') virtualScroll: VirtualScroll;

...

    this.getItems().then(() => { 
      this.virtualScroll.resize();
    });

Error:
Uncaught (in promise): TypeError: _this.virtualScroll.resize is not a function

Any better ideas???

Hmmm, that's interesting. Looking into this now.

Actually, @daveshirman , is that logic inside of a lifecycle event or in the constructor?

GetItems() is a promise that gets the data from a local db in ngOnInit().

@daveshirman, instead of getting that data in ngOnInit could you try `ionViewDidLoad'?

And then call the resize in ionViewDidLoad too

Most likely you are calling resize before the virtualScroll component has actually rendered to the dom, therefore causing the error you posted.

I tried ALL the life cycle events in the ionic 2 API. You can modify and
try them in the plunkr if you want to double check as you can see this
issue there.

@jgw96 not so I'm afraid, I've modified the plunkr to illustrate your assumption is incorrect, you would expect to see an alert(1), but no dice:

http://plnkr.co/edit/etNNT8tKJB4yKMVV0F7a?p=preview

What else could be wrong?

Alright @daveshirman , so first an apology for not noticing this sooner. The issue here was that ViewChild, in this case, was returning a reference to the ion-list that virtualScroll was on, and ion-list obviously does not have a resize method. I have made a plunker here that shows the correct way to get a reference to virtualscroll.

@jgw96 Thanks for this, couple of things:

  1. I am not aware of the syntax {read: ... } in your example on the @ViewChild line. Is this in the docs?

  2. Whilst the resize method is now available, it doesn't actually do anything/fix the problem.

If you load your plunkr, then scroll slightly, you can see all the rows realign. This is what the resize should do/the VirtualScroll component should do regardless!

Thanks.

I haven't tried yet, but it is very interesting. Good work!

@daveshirman good questions.

Question 1: This syntax is not something that is specific to Ionic, but it is covered in the angular docs.

Question 2: I will look into a better way to do this (:

I have tried the workaround by resizing the virtualScroll as metionioned by @jgw96, the items are still overlapping. My virtualscroll consists of cards with text content, and sometimes video's/images.

Here's how I did it, for now:

http://www.codingandclimbing.co.uk/blog/ionic-2-fix-virtualscroll-overlapping-items-bug

On 27 May 2017 12:20 pm, "raym0nd93" notifications@github.com wrote:

I have tried the workaround by resizing the virtualScroll as metionioned
by @jgw96 https://github.com/jgw96, the items are still overlapping. My
virtualscroll consists of cards with text content, and sometimes
video's/images.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/driftyco/ionic/issues/11542#issuecomment-304445898,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ANnlXn7EDbPLV3ENBkzCUdhcDkvBTJBPks5r-AcAgaJpZM4NTIe7
.

@daveshirman Thanks for helping out.

The solution is not working for me, maybe this is because I'm using variable height on my items? the text items are a lot smaller in height then the video/image items. Any ideas?

So am I.

Try changing the timeout value maybe.

On 27 May 2017 12:53 pm, "raym0nd93" notifications@github.com wrote:

@daveshirman https://github.com/daveshirman Thanks for helping out.

The solution is not working for me, maybe this is because I'm using
variable height on my items? the text items are a lot smaller in height
then the video/image items. Any ideas?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/driftyco/ionic/issues/11542#issuecomment-304447482,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ANnlXvdUdzFEOldzBPOe5bfToxVstjPkks5r-A7PgaJpZM4NTIe7
.

I resize the virtualscroll when all data from server is loaded. I've tried a timeout(after data load) up to 2 seconds, still not working.

Is there any update on that issue? I have a variable height component inside virtualItem and I have the same problem.

The workarounds provided in this thread are not working for me.

My STRONG advice is to find a way around using virtual scroll. Make your
list filtered in some way that means you can render all the items normally.

Virtual Scroll is completely and utterly broken and not worth wasting time
on until someone from the Ionic team acknowledges the multitude of issues
surrounding it and fixes them.

But then they seem far more focused on PWA matters to bother with trivial
things like making a stable and robust framework...

Maybe if this gets enough upvotes someone will actually do something? Who
knows.

On 6 Feb 2018 12:48, "Robson Garcia" notifications@github.com wrote:

Is there any update on that issue? I have a variable height component
inside virtualItem and I have the same problem.

The workarounds provided in this thread are not working for me.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ionic-team/ionic/issues/11542#issuecomment-363411781,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ANnlXvRiMJBeA2N9n-n6SUlPEpDs0EFXks5tSEoXgaJpZM4NTIe7
.

They have been working on it and merged it in the core branch. But I didn't test it yet.
https://github.com/ionic-team/ionic/commits/core

https://www.webcomponents.org/element/PolymerElements/iron-list is working great for me.

@RafaelKr How we can use https://www.webcomponents.org/element/PolymerElements/iron-list in ionic project ? Kindly guide with a step by step method please.

Is there any way in Ionic to display image from array , I had tried too much but cant find any way ,
Please can anyone help me for the same.

@RafaelKr I would love to try iron-list too. Can you give us two/three tips on how to install it?

@rahulvyas did you tried to install?

@andreandev Nope still waiting for @RafaelKr to respond.

@rahulvyas @andreandev

Hi, I don't recommend using iron-list in Ionic, as you have to implement Polymer and you can't use Angular (Ionic) components inside Polymer Elements (Elements used for styling like ion-grid can be used, but no ion-cards for examle). Also you have to deal with bower, another package manager additionally to npm.
Maybe this is an alternative, but I didn't test it until now: https://github.com/mgnstudio7/stenciljs-virtual-scroll

If you want to use iron-list, here are the steps I took:

  • Use an own branch in git or make a copy of your existing Ionic project folder
  • cd into your Ionic project directory
  • Install origami, to use Polymer Elements in Angular: npm i --save @codebakery/origami
  • Go into your app.module.ts and add this:
...
import { PolymerModule } from '@codebakery/origami'

...

@NgModule({
  ...
  imports: [
    ...
    PolymerModule.forRoot()
  ],
  ...
})
export class AppModule {}
  • If you're using lazy loading, make your module of the component where you want to use Polymer Elements look like this, else add CUSTOM_ELEMENTS_SCHEMA to the AppModule:
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'
import { IonicModule } from 'ionic-angular'

import { PolymerModule } from '@codebakery/origami'
import { FeedListComponent } from './feed-list'

@NgModule({
  declarations: [
    FeedListComponent
  ],
  imports: [
    IonicModule,
    PolymerModule.forRoot()
  ],
  exports: [
    FeedListComponent
  ],
  schemas: [
    CUSTOM_ELEMENTS_SCHEMA
  ]
})
export class FeedListModule {}
  • Install and init bower:
npm i -g bower
npm i -D bower
bower init
  • Create a .bowerrc file on the same folder level as the newly created bower.json file with the following content:
{
  "directory": "src/assets/bower_components"
}
  • Add this folder to your .gitignore: src/assets/bower_components/
  • Add this line to the scripts-section in your package.json: "postinstall": "bower install",
  • Install the following bower-packages:
    bower install --save webcomponentsjs polymer iron-list
    Additonally I installed iron-flex-layout, plastic-image and paper-card (as a replacement for ion-card).
  • Create the file src/assets/elements.html with the following content:
<link href="bower_components/polymer/polymer.html" rel="import">
<link href="bower_components/iron-list/iron-list.html" rel="import">

You also have to import every other bower_component you want to use there.

  • Go into your src/index.html, add the following lines at the end of your head:
<script src="assets/bower_components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="assets/elements.html">

For using iron-flex-layout I also added this on the top of my body:

<custom-style>
  <style include="iron-flex iron-positioning iron-flex-alignment"></style>
</custom-style>
  • Modify your src/app/main.ts:
...
import { webcomponentsReady } from '@codebakery/origami'
...

// replace this line
// platformBrowserDynamic().bootstrapModule(AppModule)

// with the following
webcomponentsReady().then(() => {
  platformBrowserDynamic().bootstrapModule(AppModule)
}).catch(error => {
  // No WebComponent support and webcomponentsjs is not loaded
  console.error(error)
})

Now you should be ready to use iron-list in Ionic 2/3.
Add this to your html:

<iron-list #ironList items="[]" as="item">
  <template [polymer]="this" ngNonBindable>
    [[ item.name ]]
  </template>
</iron-list>

Use this in in your Component to add items to the list:

@ViewChild('ironList') ironListRef: ElementRef

addItemsToIronList(items: any[]) {
  let ironList = this.ironListRef.nativeElement

  if (!ironList || !ironList.items) {
    return
  }

  ironList.push('items', ...items)
}

I hope I didn't forget something, as I extracted all these steps from my git history.
Let me know, if it's working for you. Good Luck.
Maybe you want to try https://github.com/mgnstudio7/stenciljs-virtual-scroll first, if that's working, please also let me know!

Thanks @RafaelKr, only a clarification.
Can you send an example of the FeedListComponent?

There you go:
feed-list.html
feed-list.ts (Unfortunately pastebin doesn't support TypeScript syntax highlighting)
I removed some code specific to my app, but I kept everything related to Polymer and iron-list usage.

Thanks @RafaelKr it works but i agree with you, it doesn't recommend using iron-list in Ionic, as you have to implement Polymer.

I am having a very similar issue. In my case I show list of items. Each item should be displayed in a new row. But when orientation is changed, items get overlapped. Two items displayed in one row overlapping with each other.
https://github.com/ionic-team/ionic/issues/14706

My workaround was to set the cell width manually and then resize the VirtualScroll.
Like this,

for (let i = 0; i < this.virtualScroll._cells.length; i++) {
    this.virtualScroll._cells[i].width = width; //set device width correctly taking orientation into account
}
this.virtualScroll.resize();

I show a overlay with a small timeout so that user cannot see the refreshing which is bit ugly.
Not fully tested but seems ok so far.
May be you could try setting the cell width.

can someone explain how this work around by @jgw96 works? because it works for me hoping for some explanation

This issue has been automatically identified as an Ionic 3 issue. We recently moved Ionic 3 to its own repository. I am moving this issue to the repository for Ionic 3. Please track this issue over there.

If I've made a mistake, and if this issue is still relevant to Ionic 4, please let the Ionic Framework team know!

Thank you for using Ionic!

Was this page helpful?
0 / 5 - 0 ratings