1

What I am trying to do is to create an anchor link. This link will navigate to a specific scroll point in my page. I have Angular version 5.

Html:

<mat-list>
     <mat-list-item><a [routerLink]="['/']"> Intro </a></mat-list-item>
     <mat-list-item><a [routerLink]="['/']" fragment="mobile"> Mobile </a></mat-list-item>     
     ...
</mat-list>

In home.componets.ts:

export class HomeGrComponent implements OnInit {
    private fragment: string;

constructor(private route: ActivatedRoute) { }

ngOnInit() {        
    this.route.fragment.subscribe(fragment => { this.fragment = fragment; });
}

ngAfterViewInit(): void {
    try {
        setTimeout(()=> {
            document.querySelector('#' + this.fragment).scrollIntoView();
        }, 1000);

    } catch (e) { }
  }    
}

I took this code from this question but it doesn't work. Url is changed to

http://localhost:4200/#mobile

but it didn't scroll to my point. Also in console there is an error:

Cannot read property 'scrollIntoView' of null 

What can be possible goes wrong? If you need some additional information please ask me to reply. Also it could be great the scroll navigates smoothly (optional).

Vasilis Greece
  • 861
  • 1
  • 18
  • 38

3 Answers3

2

You can use the following Code:

import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { filter } from 'rxjs/operators';
import { Subscription } from 'rxjs';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnDestroy {
  private sub: Subscription;

  constructor(activeRoute: ActivatedRoute) {
    this.sub = activeRoute.fragment.pipe(filter(f => !!f)).subscribe(f => document.getElementById(f).scrollIntoView());
  }

  public ngOnDestroy(): void {
    if(this.sub) this.sub.unsubscribe();
  }
}

Working example and Code behind

Markai
  • 2,098
  • 1
  • 10
  • 15
  • That is working. Do you have an idea where to put a code for a smooth scroll? – Vasilis Greece Feb 22 '18 at 10:41
  • 1) in ngOnDestroy when I put a console.log message, it never appears I don't know how it works, 2) the first problem is when the page is refreshing with /#mobile it says Cannot read property 'scrollIntoView' of null and on page shows nothing, 3) the second problem after the click, if I want to scroll somewhere else and then if I click again the same button, it didn't navigates me to the point, 4) scrollIntoView function it didn't recognize smooth command. Can I do in other way somehow - a smooth scrolling navigation? – Vasilis Greece Feb 23 '18 at 18:41
1

The reason why it's not working is that ngAfterViewInit is being called before the Observable is resolved, and therefore this.fragment is null, so no element is found

ngOnInit() {        
    this.route.fragment.subscribe(fragment => {
        this.fragment = fragment;
    });
}

ngAfterViewInit(): void {
    let interval = setInterval(()=> {
        let elem = document.getElementById(this.fragment);
        if(elem) {
            elem.scrollIntoView();
            clearInterval(interval);
        }
    }, 1000);  
}
Nikola Gavric
  • 3,507
  • 1
  • 8
  • 16
0

Another option is to use setTimout(). So you don't need clearInterval(). You can also access the fragment with the help of the ActivatedRoute

constructor(private route: ActivatedRoute) {}

ngAfterViewInit(): void {
           setTimeout(() => document.querySelector(this.route.snapshot.fragment).scrollIntoView(), 1000);
}
max
  • 330
  • 3
  • 13