Search code examples
javascriptangularangular-componentsangular-router

Angular 10 get router active fragment when scrolling past the fragment?


I'm trying to highlight in the navigation which active fragment you're scrolling past.

Adding the fragment & navigation to the fragment is simple and works well, example:

      class="nav-button unselectable"
      matRipple
      routerLink="/"
      fragment="features"
      [ngClass]="{ 'nav-active': (active_fragment | async) === 'features' }"

But the router obviously can't know which element you're scrolling about so I'm trying to listen on the scroll event and check the nearest element using the Y position.

But my landing page isn't a child of my navigation so the viewchild doesn't work, example:

navigation component:

  @ViewChild('features', { static: false })
  private _features: ElementRef;

  @HostListener('window:scroll', ['$event'])
  private _update_active_fragment(event: any) {
    event.preventDefault();

    console.log(window.pageYOffset);
    console.log(this._features.nativeElement);
  }

Landing page component:

  <app-features #features id="features"></app-features>

But features native element is undefined.

My question is:

  • How else can I achieve this feature?
  • How can I get the element ref of from the navigation component?
  • How can I get the y position of the features element in the navigation component?

Solution

  • Made a new navigation service:

    public active_fragment: BehaviorSubject<string> = new BehaviorSubject('');
    
      constructor(private readonly route: ActivatedRoute) {
        this.route.fragment.subscribe((frag) => {
          this.active_fragment.next(frag);
        });
      }
    

    In my navigation component:

          [ngClass]="{
            'nav-active': (navigationService.active_fragment | async) === 'home'
          }"
    

    in my landing component that contains my fragments:

      @ViewChild('features', { read: ElementRef })
      private _features: ElementRef;
      @ViewChild('benefits', { read: ElementRef })
      private _benefits: ElementRef;
    
    
      @HostListener('window:scroll', ['$event'])
      private _update_active_fragment(event: any) {
        event.preventDefault();
        switch (true) {
          case window.pageYOffset >=
            this._some_previous_element.nativeElement.offsetTop &&
            window.pageYOffset <= this._features.nativeElement.offsetTop: {
            this.navigationService.active_fragment.next('network-rail-feedback');
            break;
          }
    
          case window.pageYOffset >= this._features.nativeElement.offsetTop &&
            window.pageYOffset <= this._benefits.nativeElement.offsetTop: {
            this.navigationService.active_fragment.next('features');
            break;
          }
    
    
          default:
            break;
        }
      }