Olts
Olts

Reputation: 163

Angular 9, scroll restoration/anchor scrolling does not work with async data loading

I am trying to scroll to an anchor after navigating by routerlink using fragments.

** Component 1 **

<a routerLink="/training/{{ currentTrainingId }}" fragment="{{currentDomainId}}">

This link should bring the user to component 2. I hoped to achieve anchor scrolling by giving the element an id and then automatically adding #id in the URL using fragments.

** Component 2 **

<div *ngIf="all data has been loaded">
    ....
    <domain-overview *ngFor="let domain of domains" [id]="domain.id"></domain-overview>
</div>

The generated URL does seem to be right.

http://localhost:4200/training/28#40

However, the anchor scrolling does not happen. I think it has something to do with asynchronously loading data. The domains have not loaded yet when anchor scrolling is executed..

I have created a static div and then the anchor scrolling works.

Does anyone have any idea how to deal with async data and anchor scrolling?

Solution

Do not rely on the automatic anchor scrolling, but instead program your own scroll function. Based on @Vinaayakh his answers I got the following working solution.

scroll(id){
    const elmnt = document.getElementById(id);
    elmnt.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
}

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

Later, after loading all data in the complete section of the subscription, I call the scroll function.

setTimeout(() => {
    this.scroll(this.fragment);
 }, 250);

Upvotes: 7

Views: 8376

Answers (2)

Geogram
Geogram

Reputation: 140

Update to include ActivatedRoute.snapshot (property) you can use without subscribing to the route fragment:

constructor(private route: ActivatedRoute){
    this.fragment = this.route.snapshot.fragment
}

Then in your ngOnInit:

if(!!this.fragment){
    this.scroll(this.fragment)
}

You can throw the if statement inside a setTimeout if needed, but this simplifies the code while not needing the unsubscribe in ngOnDestroy.

Upvotes: 2

Vinaayakh
Vinaayakh

Reputation: 522

Try adding this function

scroll(id){
    const elmnt = document.getElementById(id);
    elmnt.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
}

and add the function to HTML

<domain-overview *ngFor="let domain of domains" (click)="scroll(id)" [id]="domain.id"></domain-overview>

Upvotes: 6

Related Questions