Skip to content

bug: A cached page's virtual-scroll doesn't re-render on window resize (Keyboard or Orientation) #19264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
omardoma opened this issue Sep 4, 2019 · 24 comments
Labels

Comments

@omardoma
Copy link

omardoma commented Sep 4, 2019

Bug Report

If you have a route that contains an ion-virtual-scroll, then you navigate forward (So the previous route is cached and reused), if the new current page triggers a resize, then you go back to the cached route, the virtual scroll items will collapse and overlap each others.

Ionic version:
[x] 4.8.1

Current behavior:
An ion-virtual-scroll existing on a cached route doesn't react to screen resizes and it collapses when navigating back to its page.

Expected behavior:

ion-virtual-scroll should react to screen resizes even if its page is not the active one.

Steps to reproduce:
Tabs are affected heavily because all of their views are cached and reused

It happens on all platforms and on both, virtual devices and real devices.

Screen Recording 2019-09-04 at 1 08 00 PM

Other information:

#18409

Ionic info:

Ionic:

   Ionic CLI                     : 5.2.7
   Ionic Framework               : @ionic/angular 4.8.1
   @angular-devkit/build-angular : 0.801.3
   @angular-devkit/schematics    : 8.1.3
   @angular/cli                  : 8.1.3
   @ionic/angular-toolkit        : 2.0.0

Cordova:

   Cordova CLI       : 9.0.0 ([email protected])
   Cordova Platforms : android 8.0.0, ios 5.0.1
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 4.1.0, (and 15 other plugins)

Utility:

   cordova-res : 0.6.0 
   native-run  : 0.2.8 

System:

   Android SDK Tools : 26.1.1 (/Users/omardoma/Library/Android/sdk)
   ios-deploy        : 1.9.4
   ios-sim           : 8.0.2
   NodeJS            : v10.15.3 (/usr/local/Cellar/node@10/10.15.3/bin/node)
   npm               : 6.10.3
   OS                : macOS Mojave
   Xcode             : Xcode 10.3 Build version 10G8
@ionitron-bot ionitron-bot bot added the triage label Sep 4, 2019
@omardoma
Copy link
Author

omardoma commented Sep 10, 2019

@manucorporat I think its related to the code merged for #18878, the same bug existed in Ionic 3.8.x and was fixed in Ionic 3.9.0 #13143.

This issue is preventing me from going to production, its very urgent, can you or anyone of the team update us with the status ?

@omardoma
Copy link
Author

omardoma commented Sep 19, 2019

Guys, its been over two weeks since I have created the issue and have supplied all of the reproducing steps, and even provided a hint on the culprit, nobody seems to be checking any virtual scroll related issues or even commenting with acknowledgements or workarounds.

Its very frustrating not being able to fix a major issue that our production app is facing because of the usage of the virtual scroll that nobody at Ionic seems to give any attention to, while I believe that its one of the most important components in Ionic, as its needed to minimize performance gaps of hybrid apps!

@pseudooriginal
Copy link

This is just unbelievable that nobody from Ionic just look at this bug. It is still here in 4.11.2.

@omardoma
Copy link
Author

@liamdebeasi Hey, can we please get an update on this issue, Its affecting our production app UX greatly, seems like anything related to virtual-scroll is ignored even though its a critical component for many apps.

@MarkChrisLevy
Copy link
Contributor

MarkChrisLevy commented Nov 13, 2019

@omardoma I also suffer because of that, but until it is fixed you may try following code:

export class YourComponent  {

    private virtualScrollRerender: boolean;

    @ViewChild(IonVirtualScroll, {static: false})
    private virtualScroll: IonVirtualScroll;

    private viewActive: boolean;

    @HostListener("window:resize")
    protected windowResized() {
        if (!this.viewActive) {
            this.virtualScrollRerender = true;
        }
    }

    ionViewDidEnter() {
        this.viewActive = true;
        if (this.virtualScroll && this.virtualScrollRerender) {
            this.virtualScroll.checkRange(0);
            this.virtualScrollRerender = false;
        }
    }

    ionViewDidLeave() {
        this.viewActive = false;
    }

}

The downside of this solution is that scroll position can be different than it was before you left the view, but at least it renders correctly.

@TdoubleG
Copy link

TdoubleG commented Dec 4, 2019

3 Month past, and still no comment from ionic devs...

@brandyscarney @adamdbradley

@nikosdouvlis
Copy link
Contributor

This is a show stopped for our team as well. No workarounds for now

@mhartington
Copy link
Contributor

mhartington commented Dec 16, 2019

Hey everyone! Just an update here.

We're going to be pushing folks to use Angular's CDK Scroller for virtual scrolling instead of our virtual scroller. A big reason why is that CDK Scroller is a framework maintained solution, therefore support/performance are guaranteed. At this time, we're not going to be pushing fixes for our virtual scroller.

For reference, I put together this repo which uses the Angular CDK scroller and Ionic, and everything was working as expected. Even browser resizing/items not collapsing.

https://github.com/mhartington/cdk-virtual-scroll-ionic

I highly suggest people start using the CDK scroller in their apps now, as we'll eventually remove virtual scroll from the framework specific bindings.

@omardoma
Copy link
Author

omardoma commented Dec 16, 2019

Hey everyone! Just an update here.

We're going to be pushing folks to use Angular's CDK Scroller for virtual scrolling instead of our virtual scroller. A big reason why is that CDK Scroller is a framework maintained solution, therefore support/performance are guaranteed. At this time, we're not going to be pushing fixes for our virtual scroller.

For reference, I put together this repo which uses the Angular CDK scroller and Ionic, and everything was working as expected. Even browser resizing/items not collapsing.

https://github.com/mhartington/cdk-virtual-scroll-ionic

I highly suggest people start using the CDK scroller in their apps now, as we'll eventually remove virtual scroll from the framework specific bindings.

Hey @mhartington, thanks for the update and for providing the example, however I am afraid that using the CDK scroller causes problems when used with ion-infinite-scroll and ion-refresher, please check this thread to know more about the issues, is there a workaround or a specific way to use them together at the moment?

@masimplo
Copy link
Contributor

Hey @mhartington I know you've done some fiddling in the past with CDK's VS but never got around to bringing this into Ionic. At that time I had also tried moving from Ionic to CDK as I imagined something like this might happen, but faced multiple issues on migrating.
To be totally honest, it is not an ideal situation to stop maintaining something and pushing users of Ionic to migrate right away to something that has no direct migration path, without instructions on how to migrate. For instance CDK has no support for headers/footers and no getPositionForItem function. Also it is another thing to build something on top of CDK and offer it as part of Ionic and a totally different one to ask every single user to integrate it with Ionic (i.e. on-infinite-scroll and ion-refresher mentioned above).
If you are indeed going to drop VS from Ionic, a deprecation message together with some instructions on how CDK can be a direct replacement for Ionic VS will be extremely helpful.

@ccroy
Copy link

ccroy commented Dec 19, 2019

Hey guys, I had the same problem and went down a few paths before coming up with a solution that, so far, works for me... hopefully this works for others as well.

FYI I've only tried this using Angular 8.1.2, interfacing with ionic serve as devapp on iPad Mini 4 (ionic serve --devapp).

My approach:

  1. Subscribe to angular's router events. I did this inside ngInit() of the page that contains the virtual scroller.
  2. If the incoming router event is an instance of NavigationEnd AND it matches the component selector for the page we are interested in, then dispatch a new 'resize' event on the window to induce the virtual scroll to resize.
  3. Unsubscribe from the events in ngDestroy(), so that if we init the page more than once we don't have multiple router event subscriptions doing the same thing.

The code:

import { Router, NavigationEnd } from '@angular/router';
import { Subscription } from 'rxjs';

const SELECTOR = 'scroll-fix-example';

@Component({
    selector: SELECTOR,
    templateUrl: ...
    styleUrls: ...
})
export class ScrollFixExamplePage implements OnInit {
    private routerSub: Subscription;
    constructor(
        public router: Router
    ) {}

    ngOnInit() {
        this.routerSub = this.router.events.subscribe(e => {
            if(e instanceof NavigationEnd && e.url.includes(SELECTOR)) {
                window.dispatchEvent(new Event('resize'));
            }
        });
    }

    ngOnDestroy() {
        this.routerSub.unsubscribe();
        console.info('Unsubscribed from router events');
    }
...

There's probably a better event to use to induce the resizing sooner than the NavigationEnd event, which may provide a better UX. Let me know your thoughts on this.

Edit:
I just noticed @MarkChrisLevy's workaround from Nov. 13, which looks like effectively the same approach that yields the same outcome, with the same downside being that the scroll position is likely different from before leaving the view.

@amin79
Copy link

amin79 commented May 3, 2020

@omardoma Hi. I exactly have the same problem in a same scenario. I navigate to chat page, open keyboard and navigate back and cards are overlapped. I tried andular CDK and had same problem. It didn't overlap, but didn't show the cards correctly and juts renders 2 or 3 of them. Did you find any solution for that? It's about a week I'm looking for a solution.

@eddyuan
Copy link

eddyuan commented Jul 7, 2020

a lazy workaround would be
ionViewWillEnter() { window.dispatchEvent(new Event('resize')); }

@veerasep6
Copy link

i am using window.dispatchEvent(new Event ('resize')); .. virtual item was rerendered.. but list item was coming for duplicate items and my scroll position was change.. plz solve this issue..

@veerasep6
Copy link

First screen

Screenshot_20200710_234906_com jdf joindfametest

Second go to post page.. now open keyboard

Screenshot_20200710_234914_com jdf joindfametest

Third my first card post was changed and coming for duplicates
Screenshot_20200710_235002_com jdf joindfametest

@arcbus
Copy link

arcbus commented Nov 10, 2020

the window resize hack kind of works

 window.dispatchEvent(new Event('resize'));

Except that sometimes (always?) when you go back to the screen with virtual scroll, it doesn't put you back at the position you were at.

EDIT: i think the mis-positioning in scroll can be mitigated by making sure that your virtual scroll items are all the same height, and match the approxItemHeight passed in to virtual scroll. I think it's just too dumb to add up the heights of items, and just uses this approx height to get back to position it thinks it was in

@MilotH2
Copy link

MilotH2 commented Feb 25, 2021

I am facing the same issue... when i switch to another tab that has an input, and the keyboard opens up, then i switch back to the tab that has ion-virtual-scroll, it does exactly this.

@studioromeo
Copy link
Contributor

studioromeo commented Mar 26, 2021

Hey Ionic / @mhartington. Thanks for your advisory to use the CDK virtual scroller. Is this still Ionic's held position? It's not clear in the docs whether ion-virtual-scroll is deprecated or not. If so, would you mind adding a note (or accepting a pr) in the docs that communicates this?

@shapebuster
Copy link

Facing the same issue. Would be nice if Ionic had a look.

@casper5822
Copy link

Any update on this bug guys? We have a ionic 5 app and there is the same problem.

@studioromeo
Copy link
Contributor

Hey everyone. Not sure if this really helps with this specific issue but the Ionic guys have recently clarified their position on the future of the virtual scroller

In Framework v6, the ion-virtual-scroll component has been deprecated in favor of using framework-specific solutions. Given the complex nature of virtual scrolling and that there are already many great 3rd party solutions, we felt it was better to use those solutions instead.

See https://beta.ionicframework.com/docs/api/virtual-scroll for a migration guide. ion-virtual-scroll will be removed in Framework v7, and developers do not need to migrate off this component to upgrade to Framework v6.

@somnathk27896
Copy link

somnathk27896 commented Sep 17, 2021

Angular virtual scroller yet not compatible with ion-refresher and ion-infinite-scroller so I continued using ion-virtual-scroller so I added some fixes to make it smooth and it is working perfect ( data getting persisted on back)


HTML -
<ion-content scrollEvents="true" (ionScroll)="getScrollPosition()">
    <ion-virtual-scroll [items]="itemList " approxItemHeight="56px">
        <ion-item *virtualItem="let item" (click)="GoToDetails(item)"  class="opacity-1">
                    {{  item  }}
        </ion-item>
    </ion-virtual-scroll>
</ion-content>

TS-

@Component({
    templateUrl: ...
    styleUrls: ...
})
export class ScrollFixExamplePage implements OnInit {
    constructor(
        private elementRef: ElementRef
    ) {}

      @ViewChild(IonContent) content: IonContent;
      this.scrollPosition: number = 0;
      itemList = [  ]// List of data to display in virtual scroller

  ionViewWillEnter(){
    if (this.itemList.length <= 0 ) { //condition for initial page load  

        /*  API call to get data  */
         this.getData().subscribe(data => {
              this.itemList  = data; 
         })


    }else{ // else  persist page state from where you leaved

      //It will take you to place from where you leaved page
      this.content.scrollByPoint(0, this.scrollPosition, 0).then(() => {});
      
    }
  }

    ionViewDidLeave(){
      this.elementRef.nativeElememt.remove();
    }


  getScrollPosition(){
    this.content.getScrollElement().then(x => {
      this.scrollPosition = x.scrollTop;
    });
  }

@liamdebeasi
Copy link
Contributor

Thanks for the issue! With the release of Ionic 6 we will be deprecating ion-virtual-scroll in favor of JavaScript Framework solutions. As a result, we have a freeze on new development with the exception of critical bugs, such as security issues.

Using these new virtual scrolling solutions should provide a better developer experience, more performant app, and fewer bugs! We have created migration guides for the main 3 JavaScript Frameworks Ionic supports to make this migration easy for developers.

Migration for Angular users: https://ionicframework.com/docs/angular/virtual-scroll
Migration for React users: https://ionicframework.com/docs/react/virtual-scroll
Migration for Vue users: https://ionicframework.com/docs/vue/virtual-scroll

The documentation for ion-virtual-scroll still exists at https://ionicframework.com/docs/api/virtual-scroll.

ion-virtual-scroll will be removed in Ionic 7. Developers do not need to migrate off ion-virtual-scroll in order to upgrade to Ionic 6 or to continue using it in Ionic 4/5.

I am going to close this issue. Thank you! We are tracking issues with components like ion-refresher when using these JS Framework solutions in #23437.

@ionitron-bot
Copy link

ionitron-bot bot commented Nov 6, 2021

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Nov 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests