156

I wish to add some links on my Angular2 page, that when click, will jump to specific positions within that page, like what normal hashtags do. So the links would be something like

/users/123#userInfo
/users/123#userPhoto
/users/123#userLikes

etc.

I don't think I need HashLocationStrategy, as I'm fine with the normal Angular2 way, but if I add directly, the link would actually jump to the root, not somewhere on the same page. Any direction is appreciated, thanks.

Stone
  • 1,811
  • 2
  • 14
  • 14

21 Answers21

181

Update

This is now supported

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

Add Below code to your component to scroll

  import {ActivatedRoute} from '@angular/router'; // <-- do not forget to import

  private fragment: string;

  constructor(private route: ActivatedRoute) { }

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

  ngAfterViewInit(): void {
    try {
      document.querySelector('#' + this.fragment).scrollIntoView();
    } catch (e) { }
  }

Original

This is a known issue and tracked at https://github.com/angular/angular/issues/6595

Mohammad Kermani
  • 5,188
  • 7
  • 37
  • 61
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • what does `id` refer to? – invot Sep 06 '16 at 19:27
  • 1
    @invot a variable with a string (for example what `123` is in the question) assuming that the route path expects a parameter like `{ path: 'users/:id', ....}` – Günter Zöchbauer Sep 06 '16 at 19:30
  • What if I want the #anchor to appear only if fragment is not null/undefined? Currently I still have http://somethi.ng/page#. If there's no anchor it should just be http://somethi.ng/page. If there's an anchor it should still normally be http://somethi.ng/page#anchor. – Kunepro Nov 17 '16 at 16:49
  • 2
    If you want to scroll to the anchor see this post: https://github.com/angular/angular/issues/6595 – pearpages Jan 11 '17 at 15:13
  • 18
    Note: this still doesn't scroll – Martín Coll Feb 14 '17 at 08:48
  • 1
    @GünterZöchbauer last change not scroll with me – Amr Ibrahim Sep 21 '17 at 14:59
  • @amrabdulaziz I wasn't convince your edit was the best solution. Thanks anyway :). I don't have a project set up to try it out. Could you please try to wrap `document.querySelector('#' + this.fragment).scrollIntoView();` with `setTimeout(() { ...})`, to see if it works this way? – Günter Zöchbauer Sep 21 '17 at 15:02
  • 2
    yes it works with setTimeout, if i found better solution i will let you know – Amr Ibrahim Sep 21 '17 at 15:03
  • Can you please explain what is the advantage of `ngAfterViewInit` compared to https://stackoverflow.com/a/45357991/1182474 ? – David L. Jan 15 '18 at 15:06
  • @GünterZöchbauer does it work also if the router link is few components away from the anchor (child of a sibling)? – mpro Mar 01 '18 at 15:04
  • @mpro It is at least supposed to work this way. The issue is still open, so it might not work at all. I haven't used it myself since. – Günter Zöchbauer Mar 01 '18 at 16:13
  • 3
    For those struggling to scroll to number-like ids, mind, that `01` or `100` are not valid CSS selectors. You might want to add a letter or something to make it a valid selector. So you would still pass`01` as a fragment, but the `id` would need to be something like `d01`and thus `document.querySelector('#d'+id)` would match. – pop Mar 15 '18 at 22:01
  • I added my solution to make it scroll when on the same page too. basically just add this into the `` tag : `(click)="window.location = '#Test';"` – Worthy7 Sep 19 '18 at 01:08
  • this solution gives me this error Syntax error, unrecognized expression: /service-details/1139#overview because there is no path which includes # parth so what to do now @GünterZöchbauer – Aarsh Dec 21 '18 at 05:46
86

Sorry for answering it bit late; There is a pre-defined function in the Angular Routing Documentation which helps us in routing with a hashtag to page anchor i.e, anchorScrolling: 'enabled'

Step-1:- First Import the RouterModule in the app.module.ts file:-

imports:[ 
    BrowserModule, 
    FormsModule,
    RouterModule.forRoot(routes,{
      anchorScrolling: 'enabled'
    })
  ],

Step-2:- Go to the HTML Page, Create the navigation and add two important attributes like [routerLink] and fragment for matching the respective Div ID's:-

<ul>
    <li> <a [routerLink] = "['/']"  fragment="home"> Home </a></li>
    <li> <a [routerLink] = "['/']"  fragment="about"> About Us </a></li>
  <li> <a [routerLink] = "['/']"  fragment="contact"> Contact Us </a></li>
</ul>

Step-3:- Create a section/div by matching the ID name with the fragment:-

<section id="home" class="home-section">
      <h2>  HOME SECTION </h2>
</section>

<section id="about" class="about-section">
        <h2>  ABOUT US SECTION </h2>
</section>

<section id="contact" class="contact-section">
        <h2>  CONTACT US SECTION </h2>
</section>

For your reference, I have added the example below by creating a small demo which helps to solve your problem.

Demo : https://routing-hashtag-page-anchors.stackblitz.io/

Naheed Shareef
  • 1,011
  • 7
  • 5
  • 1
    Thanks very much for this. Clean, concise and it works! – Belmiris Dec 31 '18 at 18:49
  • 4
    Yes, Thanks, for auto-scoll on page load with Angular 7, just have to add ```scrollPositionRestoration: 'enabled',``` under anchorScrolling option :) – Mickaël Jan 30 '19 at 23:32
  • 2
    This appends the hash to the end of my url properly, but it doesn't anchor to the div with the same name. I'm not sure what I'm missing. I followed the three steps above. – oaklandrichie Aug 20 '19 at 22:53
  • @oaklandrichie: Can you share jsfiddle / stackblitz code here. I can help you out – Naheed Shareef Aug 22 '19 at 04:51
  • this answer definetely should be accepted, works like charm! – Kiss Koppány Mar 29 '20 at 23:00
  • Thanx, man! That's exactly what I have been looking for. The only thing when it doesn't work is when user clicks on the same link second time (when the fragment already exists in the URL). But I've managed find another parameter for the routing options: onSameUrlNavigation: 'reload', which helps for such cases. (Use this parameter along with anchorScrolling: 'enabled') – Aviw Nov 08 '20 at 20:28
54

Although Günter's answer is correct, it doesn't cover the "jump to" the anchor tag part.

Therefore, additionally to:

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

... in the component (parent) where you need a "jump to" behavior, add:

import { Router, NavigationEnd } from '@angular/router';

class MyAppComponent {
  constructor(router: Router) {

    router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = router.parseUrl(router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(true); }
        }
      }
    });

  }
}

Please note that this is a workaround! Follow this github issue for future updates. Credits to Victor Savkin for providing the solution!

Sibiraj
  • 4,486
  • 7
  • 33
  • 57
Kaloyan Kosev
  • 12,483
  • 8
  • 59
  • 90
  • hello, i'm making an FAQ page where you can jump to the answer by clicking on a question defined in a list on top of the page. So the user is already on the current page when he jumps to the anchor. If i want the routerLink attribute to work i have to give `"['../faq']"` as the value or else it will try to jump to /faq/faq/#anchor, insteaf of /faq/#anchor. Is this the correct way to do it or is there a more elegant way to refer to the current page in routerlink? Also, `document.querySelector("#" + tree.fragment);` gives me an not a valid selector error. Are you sure this is correct?Thank you – Maurice Jun 24 '18 at 12:23
  • 2
    when you click again on the same link it does not work. Did anybody make this work if user click on the same anchor link ``? – Junior Mayhé Aug 29 '18 at 14:53
  • @JuniorM Did you ever figure this out? I'm running into the same issue. – The Muffin Man Oct 28 '18 at 18:00
  • @Muffin, have a try with something like this https://github.com/juniormayhe/Mailing/blob/master/Mailing.SPA/src/app/faq/faq.component.ts – Junior Mayhé Oct 30 '18 at 15:38
  • 1
    This needs more exposure. This is a better answer IMO. Most people will want to jump to the section. – iamtravisw Sep 14 '19 at 21:31
27

A little late but here's an answer I found that works:

<a [routerLink]="['/path']" fragment="test" (click)="onAnchorClick()">Anchor</a>

And in the component:

constructor( private route: ActivatedRoute, private router: Router ) {}

  onAnchorClick ( ) {
    this.route.fragment.subscribe ( f => {
      const element = document.querySelector ( "#" + f )
      if ( element ) element.scrollIntoView ( element )
    });
  }

The above doesn't automatically scroll to the view if you land on a page with an anchor already, so I used the solution above in my ngInit so that it could work with that as well:

ngOnInit() {
    this.router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = this.router.parseUrl(this.router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(element); }
        }
      }
    });
  }

Make sure to import Router, ActivatedRoute and NavigationEnd at the beginning of your component and it should be all good to go.

Source

Josh1billion
  • 14,837
  • 8
  • 38
  • 48
Ali Bari
  • 441
  • 5
  • 9
  • 4
    Works for me! In case you want to navigate within the same page you're already on, use [routerLink]="['.']" – Raoul Feb 11 '18 at 18:16
  • 1
    could you explain further? this part `document.querySelector ( "#" + f )` gives me an error because it expects a selector, not a string. – Maurice Jun 24 '18 at 14:02
  • 1
    @Maurice for me this works: `element.scrollIntoView()` (without passing `element` to the function). To make it smooth, use this: `element.scrollIntoView({block: "end", behavior: "smooth"})`. – Mr. B. Jul 16 '18 at 10:22
  • Intellisense here shows that within `onAnchorClick()`, we must pass a boolean to scrollIntoView: `if (element) { element.scrollIntoView(true); }`. Now I can click twice on the same link and scroll works – Junior Mayhé Aug 29 '18 at 15:09
23

None of the previous answers worked for me. In a last ditch effort, I tried in my template:

<a (click)="onClick()">From Here</a>
<div id='foobar'>To Here</div>

With this in my .ts:

onClick(){
    let x = document.querySelector("#foobar");
    if (x){
        x.scrollIntoView();
    }
}

And it works as expected for internal links. This does not actually use anchor tags so it would not touch the URL at all.

cheese
  • 681
  • 6
  • 7
9

if it does not matter to have those element ids appended to the url, you should consider taking a look at this link:

Angular 2 - Anchor Links to Element on Current Page

// html
// add (click) event on element
<a (click)="scroll({{any-element-id}})">Scroll</a>

// in ts file, do this
scroll(sectionId) {
let element = document.getElementById(sectionId);

  if(element) {
    element.scrollIntoView(); // scroll to a particular element
  }
 }
Ramu N
  • 391
  • 4
  • 5
8

Use this for the router module in app-routing.module.ts:

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    useHash: true,
    scrollPositionRestoration: 'enabled',
    anchorScrolling: 'enabled',
    scrollOffset: [0, 64]
  })],
  exports: [RouterModule]
})

This will be in your HTML:

<a href="#/users/123#userInfo">
bunbun
  • 2,595
  • 3
  • 34
  • 52
faizal razak
  • 89
  • 1
  • 1
7

Solutions above didn't work for me... This one did it:

First, prepare MyAppComponent for automatic scrolling in ngAfterViewChecked()...

import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';

@Component( {
   [...]
} )
export class MyAppComponent implements OnInit, AfterViewChecked {

  private scrollExecuted: boolean = false;

  constructor( private activatedRoute: ActivatedRoute ) {}

  ngAfterViewChecked() {

    if ( !this.scrollExecuted ) {
      let routeFragmentSubscription: Subscription;

      // Automatic scroll
      routeFragmentSubscription =
        this.activatedRoute.fragment
          .subscribe( fragment => {
            if ( fragment ) {
              let element = document.getElementById( fragment );
              if ( element ) {
                element.scrollIntoView();

                this.scrollExecuted = true;

                // Free resources
                setTimeout(
                  () => {
                    console.log( 'routeFragmentSubscription unsubscribe' );
                    routeFragmentSubscription.unsubscribe();
                }, 1000 );

              }
            }
          } );
    }

  }

}

Then, navigate to my-app-route sending prodID hashtag

import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component( {
   [...]
} )
export class MyOtherComponent {

  constructor( private router: Router ) {}

  gotoHashtag( prodID: string ) {
    this.router.navigate( [ '/my-app-route' ], { fragment: prodID } );
  }

}
JavierFuentes
  • 1,840
  • 18
  • 13
7

In html file:

<a [fragment]="test1" [routerLink]="['./']">Go to Test 1 section</a>

<section id="test1">...</section>
<section id="test2">...</section>

In ts file:

export class PageComponent implements AfterViewInit, OnDestroy {

  private destroy$$ = new Subject();
  private fragment$$ = new BehaviorSubject<string | null>(null);
  private fragment$ = this.fragment$$.asObservable();

  constructor(private route: ActivatedRoute) {
    this.route.fragment.pipe(takeUntil(this.destroy$$)).subscribe(fragment => {
      this.fragment$$.next(fragment);
    });
  }

  public ngAfterViewInit(): void {
    this.fragment$.pipe(takeUntil(this.destroy$$)).subscribe(fragment => {
      if (!!fragment) {
        document.querySelector('#' + fragment).scrollIntoView();
      }
    });
  }

  public ngOnDestroy(): void {
    this.destroy$$.next();
    this.destroy$$.complete();
  }
}
RobC
  • 22,977
  • 20
  • 73
  • 80
6

All the other answers will work on Angular version < 6.1. But if you've got the latest version then you won't need to do these ugly hacks as Angular has fixed the issue.

here's the link to issue

All you'd need to do is set scrollOffset with the option of the second argument ofRouterModule.forRoot method.

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled',
      anchorScrolling: 'enabled',
      scrollOffset: [0, 64] // [x, y]
    })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}
आनंद
  • 2,472
  • 4
  • 21
  • 25
  • 2
    will this work for outside links? say from another website i click on www.abc.com#sectionToScrollTo – Sushmit Sagar Nov 02 '18 at 10:52
  • anchorScrolling is not working, if you make extensive use of *ngIf, because it jumps to early :-( – Jojo.Lechelt Dec 06 '18 at 15:23
  • Only problem I've had with this is timing -- it tends to jump to the anchor before some element's styling has come to full render, causing the positioning to be off. Would be nice if you could add a delay :) – Charly Feb 13 '20 at 18:28
4

Adding on to Kalyoyan's answer, this subscription is tied to the router and will live until the page is fully refreshed. When subscribing to router events in a component, be sure to unsubscribe in ngOnDestroy:

import { OnDestroy } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Subscription } from "rxjs/Rx";

class MyAppComponent implements OnDestroy {

  private subscription: Subscription;

  constructor(router: Router) {
    this.subscription = router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = router.parseUrl(router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(element); }
        }
      }
    });
  }

  public ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
DBosley
  • 88
  • 7
  • I thought subscriptions to route events were automatically torn down. –  Apr 22 '18 at 17:06
3

Since the fragment property still doesn't provide anchor scrolling, this workaround did the trick for me:

<div [routerLink]="['somepath']" fragment="Test">
  <a href="#Test">Jump to 'Test' anchor </a>
</div>
Martin Cremer
  • 5,191
  • 2
  • 32
  • 38
3

I just got this working on my own website, so I figured it would be worth posting my solution here.

<a [routerLink]="baseUrlGoesHere" fragment="nameOfYourAnchorGoesHere">Link Text!</a>

<a name="nameOfYourAnchorGoesHere"></a>
<div>They're trying to anchor to me!</div>

And then in your component, make sure you include this:

 import { ActivatedRoute } from '@angular/router';

 constructor(private route: ActivatedRoute) { 
     this.route.fragment.subscribe ( f => {
         const element = document.querySelector ( "#" + f )
         if ( element ) element.scrollIntoView ( element )
     });
 }
a_lovelace
  • 490
  • 4
  • 11
  • I think that it is better to write just `element.scrollIntoView()` or `element.scrollIntoView(true)`. Your version did not compile for me (maybe because of strictNullChecks?). – David L. Jan 15 '18 at 15:03
3

After reading all of the solutions, I looked for a component and I found one which does exactly what the original question asked for: scrolling to anchor links. https://www.npmjs.com/package/ng2-scroll-to

When you install it, you use syntax like:

// app.awesome.component.ts
@Component({
   ...
   template: `...
        <a scrollTo href="#main-section">Scroll to main section</a>
        <button scrollTo scrollTargetSelector="#test-section">Scroll to test section</a>
        <button scrollTo scrollableElementSelector="#container" scrollYTarget="0">Go top</a>
        <!-- Further content here -->
        <div id="container">
            <section id="main-section">Bla bla bla</section>
            <section id="test-section">Bla bla bla</section>
        <div>
   ...`,
})
export class AwesomeComponent {
}

It has worked really well for me.

John
  • 223
  • 3
  • 13
  • Use wheel, don't invent it again ;) – Yogen Rai Nov 11 '17 at 08:09
  • Have you looked at the code behind that component? It looks very fragile - the project also has 14 open issues - which include things like element's not existing, targets null, not scrolling to element, browser support issues. – Drenai Jan 24 '18 at 17:00
  • does not work when you have child (child has anchored entities and/or anchor names) in parent component, it just refreshes the page – Sasha Bond Jun 01 '18 at 21:45
3

A simple solution that works for pages without any query parameters, is browser back / forward, router and deep-linking compliant.

<a (click)="jumpToId('anchor1')">Go To Anchor 1</a>


ngOnInit() {

    // If your page is dynamic
    this.yourService.getWhatever()
        .then(
            data => {
            this.componentData = data;
            setTimeout(() => this.jumpToId( window.location.hash.substr(1) ), 100);
        }
    );

    // If your page is static
    // this.jumpToId( window.location.hash.substr(1) )
}

jumpToId( fragment ) {

    // Use the browser to navigate
    window.location.hash = fragment;

    // But also scroll when routing / deep-linking to dynamic page
    // or re-clicking same anchor
    if (fragment) {
        const element = document.querySelector('#' + fragment);
        if (element) element.scrollIntoView();
    }
}

The timeout is simply to allow the page to load any dynamic data "protected" by an *ngIf. This can also be used to scroll to the top of the page when changing route - just provide a default top anchor tag.

3

Unlike other answers I'd additionally also add focus() along with scrollIntoView(). Also I'm using setTimeout since it jumps to top otherwise when changing the URL. Not sure what was the reason for that but it seems setTimeout does the workaround.

Origin:

<a [routerLink] fragment="some-id" (click)="scrollIntoView('some-id')">Jump</a>

Destination:

<a id="some-id" tabindex="-1"></a>

Typescript:

scrollIntoView(anchorHash) {
    setTimeout(() => {
        const anchor = document.getElementById(anchorHash);
        if (anchor) {
            anchor.focus();
            anchor.scrollIntoView();
        }
    });
}
Hrvoje Golcic
  • 3,446
  • 1
  • 29
  • 33
2

I had the same issue. The solution : using View port Scroller https://angular.io/api/common/ViewportScroller#scrolltoanchor

-- app-routing.module.ts code :

import { PageComponent } from './page/page.component';

const routes: Routes = [
   path: 'page', component: PageComponent },
   path: 'page/:id', component: PageComponent }
];

-- Component HTML

  <a (click) = "scrollTo('typeExec')">
    <mat-icon>lens</mat-icon>
  </a>

-- Component's code :

    import { Component } from '@angular/core';
    import { ViewportScroller } from '@angular/common';


    export class ParametrageComponent {

      constructor(private viewScroller: ViewportScroller) {}

      scrollTo(tag : string)
      {
        this.viewScroller.scrollToAnchor(tag);
      }

    }
Frank Thoeny
  • 310
  • 2
  • 7
1

Here is another workaround with refernce to JavierFuentes answer:

<a [routerLink]="['self-route', id]" fragment="some-element" (click)="gotoHashtag('some-element')">Jump to Element</a>

in script:

import {ActivatedRoute} from "@angular/router";
import {Subscription} from "rxjs/Subscription";

export class Links {
    private scrollExecuted: boolean = false;

    constructor(private route: ActivatedRoute) {} 

    ngAfterViewChecked() {
            if (!this.scrollExecuted) {
              let routeFragmentSubscription: Subscription;
              routeFragmentSubscription = this.route.fragment.subscribe(fragment => {
                if (fragment) {
                  let element = document.getElementById(fragment);
                  if (element) {
                    element.scrollIntoView();
                    this.scrollExecuted = true;
                    // Free resources
                    setTimeout(
                      () => {
                        console.log('routeFragmentSubscription unsubscribe');
                        routeFragmentSubscription.unsubscribe();
                      }, 0);
                  }
                }
              });
            }
          }

        gotoHashtag(fragment: string) {
            const element = document.querySelector("#" + fragment);
            if (element) element.scrollIntoView(element);
        }
}

This allows user to directly scroll to element, if user directly lands on the page having hashtag in url.

But in this case, I have subscribed route Fragment in ngAfterViewChecked but ngAfterViewChecked() gets called continuously per every ngDoCheck and it doesn't allows user to scroll back to top, so routeFragmentSubscription.unsubscribe is called after a timeout of 0 millis after view is scrolled to element.

Additionally gotoHashtag method is defined to scroll to element when user specifically clicks on the anchor tag.

Update:

If url has querystrings, [routerLink]="['self-route', id]" in anchor wont preserve the querystrings. I tried following workaround for the same:

<a (click)="gotoHashtag('some-element')">Jump to Element</a>

constructor( private route: ActivatedRoute,
              private _router:Router) {
}
...
...

gotoHashtag(fragment: string) {
    let url = '';
    let urlWithSegments = this._router.url.split('#');

    if(urlWithSegments.length){
      url = urlWithSegments[0];
    }

    window.location.hash = fragment;
    const element = document.querySelector("#" + fragment);
    if (element) element.scrollIntoView(element);
}
Vicky Gonsalves
  • 11,593
  • 2
  • 37
  • 58
1

This one work for me !! This ngFor so it dynamically anchor tag, You need to wait them render

HTML:

<div #ngForComments *ngFor="let cm of Comments">
    <a id="Comment_{{cm.id}}" fragment="Comment_{{cm.id}}" (click)="jumpToId()">{{cm.namae}} Reply</a> Blah Blah
</div>

My ts file:

private fragment: string;
@ViewChildren('ngForComments') AnchorComments: QueryList<any>;

ngOnInit() {
      this.route.fragment.subscribe(fragment => { this.fragment = fragment; 
   });
}
ngAfterViewInit() {
    this.AnchorComments.changes.subscribe(t => {
      this.ngForRendred();
    })
}

ngForRendred() {
    this.jumpToId()
}

jumpToId() { 
    let x = document.querySelector("#" + this.fragment);
    console.log(x)
    if (x){
        x.scrollIntoView();
    }
}

Don't forget to import that ViewChildren, QueryList etc.. and add some constructor ActivatedRoute !!

Baptiste Mille-Mathias
  • 2,144
  • 4
  • 31
  • 37
0

I've just tested very useful plugin available in nmp - ngx-scroll-to, which works great for me. However it's designed for Angular 4+, but maybe somebody will find this answer helpful.

mpro
  • 14,302
  • 5
  • 28
  • 43
0

I tried most of these solutions but ran into problems leaving and coming back with another fragment it wouldn't work, so I did something a bit different that works 100%, and gets rid of the ugly hash in the URL.

tl;dr here's a better way than what I've seen so far.

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

@Component({
    selector: 'app-hero',
    templateUrl: './hero.component.html',
    styleUrls: ['./hero.component.scss']
})
export class HeroComponent implements OnInit, AfterViewChecked, OnDestroy {
    private fragment: string;
    fragSub: Subscription;

    constructor(private route: ActivatedRoute) { }

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

    ngAfterViewChecked(): void {
        try {
            document.querySelector('#' + this.fragment).scrollIntoView({behavior: 'smooth'});
            window.location.hash = "";
          } catch (e) { }
    }

    ngOnDestroy() {
        this.fragSub.unsubscribe();
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Kyle S
  • 13
  • 5