Angular4 - scroll to anchor
I am trying to do a simple scroll to an anchor element on the same page. Basically, the person clicks the "Try" button and he scrolls down to the area below the page with the id "login". Now he works with basic id="login"
and <a href="#login"></a>
, but he goes to this section. Ideally, I would like it to scroll there. If I am using Angular4, is there a built-in way to do this or which is the simplest way? Thank!
Whole template ... (component still empty)
<div id="image-header">
<div id="intro">
<h1 class="text-center">Welcome to ThinkPlan</h1>
<h3 class="text-center">Planning your way</h3>
<a class="btn btn-outline-primary" href="#login" id="view">Try It</a> <!-- Where the user clicks to scroll -->
</div>
</div>
<div class="container" id="info">
<div class="row">
<div class="col-md-12">
<div class="space" id="login"></div> <!-- The place to scroll to -->
<h1 class="text-center">ThinkPlan</h1>
<form class="form-horizontal">
<fieldset>
<legend>Login</legend>
<div class="form-group">
<label for="inputEmail" class="col-lg-2 control-label">Email</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="inputEmail" placeholder="Email">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-lg-2 control-label">Password</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="inputPassword" placeholder="Password">
</div>
</div>
<div class="form-group" id="log-btn">
<div class="col-lg-10 col-lg-offset-2">
<button routerLink="/plan" type="submit" class="btn btn-outline-primary">Login</button>
</div>
</div>
<p class="lead text-center">New here? <a routerLink="signup">Sign up.</a></p>
</fieldset>
</form>
</div>
</div>
</div>
source to share
I think this is a simpler solution:
In your HTML:
<a [routerLink]="['/']" fragment="login"></a>
In typescript:
ngOnInit() {
this.route.fragment.subscribe(fragment => { this.fragment = fragment; });
}
ngAfterViewChecked(): void {
try {
if(this.fragment) {
document.querySelector('#' + this.fragment).scrollIntoView();
}
} catch (e) { }
}
source to share
Auto scroll
Starting with Angular v6, there is a new option anchorScrolling
for RouterModule
. You can install it in the import module:
imports: [
...,
RouterModule.forRoot(routes, {anchorScrolling: 'enabled'})
Angular will automatically scroll to the element with the ID of the given fragment.
⚠️ However, this does not work when data is loaded asynchronously, see this Github issue . ⚠️
Manual scrolling
With RouterModule
smooth scrolling is not yet possible, but you can do it manually:
1) Get your target, for example with ViewChild
:
@ViewChild('pageInfo') pageInfo: ElementRef;
2) Call scrollIntoView
to nativeElement
:
const targetElement = this.pageInfo.nativeElement
targetElement.scrollIntoView({behavior: "smooth"})
source to share
With Angular 4, you might have a problem linking to the same page.
I decided to use this way
install
npm install ng2-page-scroll --save
import to your app.module.ts
import {Ng2PageScrollModule} from 'ng2-page-scroll';
@NgModule({
imports: [
/* Other imports here */
Ng2PageScrollModule
]
})
export class AppModule {
}
check it in html component
<a pageScroll href="#test">Testing</a>
<div id="test">
source to share
AfterViewCheck()
will be called every time it fires ChangeDetection
, so this is a bad solution.
Use AfterViewInit()
as
public ngAfterViewInit(): void {
this.subscription = this.route.fragment
.subscribe(fragment => {
const targetElement = this.document.querySelector('#' + fragment);
if (fragment && targetElement) {
targetElement.scrollIntoView();
} else {
window.scrollTo(0, 0);
}
});
}
public ngOnDestroy(): void {
this.subscription.unsubscribe();
}
source to share
This is a more detailed example that can be added to Sarah Dubois's answer above.
Import of router modules.
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
constructor(private route:ActivatedRoute,
private router:Router) {
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if (event.url) {
this.route.fragment.subscribe(fragment => this.fragment = fragment);
}
}
});
}
ngAfterViewChecked(): void {
try {
if(this.fragment != null) {
document.querySelector("a[name="+this.fragment+"]").scrollIntoView();
}
} catch (e) {
//console.log(e, 'error');
}
}
I love using the querySelector which will give you a lot of options on which element you want to jump to. https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
This works with Angular 8 :)
source to share