Search code examples
angularscrolllazy-loading

Angular Scroll to Next Route when page hits bottom


While scrolling down from the first route, when the page hits the end then automatically it should route to next route. As I have Lazy loaded module, I need them to appear as single page scroll through all routes.


Solution

  • You have two ways to know when an element is visible in screen:

    1.- Listening scroll event

    import {fromEvent} from 'rxjs'
    
    @ViewChild("elementBottom") element:ElementRef
    
    $obs=fromEvent(window,'scroll').pipe(
       filter(()=>{
         const position = this.element.nativeElement.getBoundingClientRect();
    
        // checking whether fully visible
        return (position.top >= 0 && position.bottom <= window.innerHeight)
       }),
       take(1)
    )
    

    2.- Using Intersection Observer

    For this you create a directive "stolen" from Sascha Wolff article like

    @Directive({
      selector: '[appIntersection]',
    })
    export class IntersectionDirective implements OnInit, OnDestroy {
      observer: IntersectionObserver;
      previousEntry: IntersectionObserverEntry;
      subscription:Subscription=null;
      @Input() rootMargin = '0px 0px 0px 0px';
      @Output() scrollEnd: EventEmitter<any> = new EventEmitter();
      constructor(private el: ElementRef,private router:Router) {}
      ngOnInit() {
        this.subscription=this.router.events.pipe(
       filter((ev)=>ev instanceof NavigationEnd)
        ).subscribe(()=>{
          this.previousEntry=null
        })
        this.observer = new IntersectionObserver(
          (entries) => {
            const entry=entries.find(x=>x.isIntersecting)
              if (!this.previousEntry?.isIntersecting && entry) {
                this.scrollEnd.emit();
                this.previousEntry = entry;
              }
          },
          {
            rootMargin: this.rootMargin,
            threshold:1
          }
        );
    
        this.observer.observe(this.el.nativeElement);
      }
      ngOnDestroy(): void {
        this.observer.disconnect();
        this.subscription && this.subscription.unsubscribe();
      }
    }
    

    Now your main.component can be like

    <router-outlet></router-outlet>
    <div appIntersection (scrollEnd)="scrollEnd()" style="height:3rem"></div>
    
    export class AppComponent  {
      constructor(private router:Router){}
      scrollEnd()
      {
        switch(this.router.url)
        {
          case "/":
            this.router.navigate(['/company']);
            break;
          case "/company":
            this.router.navigate(['/products']);
            break;
          case "/products":
            this.router.navigate(['/']);
            break;
        }
      }
    }
    

    A stackblitz

    NOTE: See that I enclosed all teh component in a div with the class whole

    .whole{
      min-height: 100vh;
    }
    

    To be sure that we need make a scroll