angularscrollportal

Keep scrolling status in Angular portals


I am running into a problem with angular portals: I have a page with a portal in it and some triggers that change the portal content. All good. When the portal changes its content, it keeps variables of rendered (inside the portal) component in memory, for instance an increment; but sadly not the scrolling position: each time the portal changes, scroll is back at top.

Does anyone knows how to solve this?

I reproduced the problem here StackBlitz:


Solution

  • try this in your widget:

    import { CdkScrollable } from "@angular/cdk/overlay";
    import {
      AfterViewChecked,
      AfterViewInit,
      Component,
      ElementRef,
      Input,
      OnDestroy,
      ViewChild
    } from "@angular/core";
    
    @Component({
      selector: "tab2",
      template: `
        <portal>
          <div
            #scrollitem
            cdkScrollable
            *ngIf="target == 2"
            style="border-style: solid; height:200px; overflow: auto"
          >
            <p>Value: {{ tab2Value }}</p>
            <button (click)="increment()">INCREMENT</button>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
            <p>INSIDE PORTAL: TAB2</p>
          </div>
        </portal>
      `,
      styles: []
    })
    export class Tab2 implements AfterViewChecked, OnDestroy {
      @Input() target: number;
    
      @ViewChild("scrollitem", { read: CdkScrollable }) scrollitem: CdkScrollable;
    
      tab2Value = 0;
    
      scrolltop = 0;
    
      subs = null;
    
      constructor() {}
      ngOnDestroy(): void {
        if (this.subs) {
          this.subs.unsubscribe();
        }
      }
    
      ngAfterViewChecked(): void {
        if (this.scrollitem) {
          this.scrollitem.scrollTo({ top: this.scrolltop });
    
          this.subs = this.scrollitem.elementScrolled().subscribe(o => {
            this.scrolltop = this.scrollitem.measureScrollOffset("top");
          });
        }
      }
    
      increment() {
        this.tab2Value++;
      }
    }
    

    Stackblitz here : https://stackblitz.com/edit/angular-ivy-2uaxdz?file=src%2Fapp%2Ftab2.component.ts