Reputation: 16949
Trying to scroll to an anchor link using the following syntax.
<a [routerLink]="['./']" fragment="test">Testing</a>
And the anchor node looks like this
<div id="test">
When clicked the browser address bar shows the #test fragment but the automatic scrolling does not occur. Any idea why it does not scroll?
Upvotes: 25
Views: 37139
Reputation: 51
My scenario was that after pressing a button at the top of the screen and receiving some data from backend I may have a message to allow the scrolling to a certain point. If the buttom is pressed again I need to be able to scroll again and again...
After using successfully
this.viewportScroller.scrollToAnchor
or
scrollIntoView
locally, I found out that it was not working in production environment (really don't know why). So,
router.navigate([], { fragment: 'yourFragment' });
Did the job, and of course I had to "clean" the fragment to enable future scrollings, so inside button's logic I added:
router.navigate(['/']);
Important: remember to configure the ExtraOptions inside app-routing.module.ts
Upvotes: 0
Reputation: 802
This is the extension of https://stackoverflow.com/a/52415783/9646878 with extra config onSameUrlNavigation: 'reload'
complete example :
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled', // or 'top'
anchorScrolling: 'enabled',
scrollOffset: [0, 64], // [x, y] - adjust scroll offset
onSameUrlNavigation: 'reload'
})
],
exports: [RouterModule]
<p>
<div id = "componentId"> </div>
</p>
onScrollTo(location: string){
setTimeout(() => { this.router.navigate([], { fragment: location }); }, 500);
}
use this method on Button click.
I used this approach for scrolling on samepage. 1.component.ts
scrollTo(fragment): void {
this.router.navigate([], { fragment: fragment }).then(res => {
const element = document.getElementById(fragment);
if (element != undefined) element.scrollIntoView();
});
}
2.component.html
<section id="some-section">
<div></div>
....
</section>
3.call the method
<a (click)="scrollTo('some-section')">Navigate to Fragment</a>
Upvotes: 8
Reputation: 335
ViewportScroller doesn't work fine on IE if your content is loaded dynamicly.
Instead you need to implement AfterViewChecked
TestComponent implements AfterViewChecked{
ngAfterViewChecked(){
var element = document.getElementById("youranchor")
element.scrollIntoView(false)
}
}
for detail,see https://angular.io/api/core/AfterViewChecked
Upvotes: 1
Reputation: 962
I have recreated an reusalbe service that can be used in any component in order to either scroll to fragment if present else to top of the page.The following contains the complete echo system in angular anchoring use through reusable service approach.
//(In service.ts)
import { Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ViewportScroller } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class RouterPathService {
constructor(
private activatedRoute: ActivatedRoute,
private viewportScroller: ViewportScroller,
) { }
scroll() {
this.activatedRoute.fragment.subscribe((fragment: string) => {
if (fragment) {
this.scrollToAnchor(fragment)
} else {
this.scrollToTop();
}
});
}
scrollToTop() {
this.viewportScroller.scrollToPosition([0, 0])
}
scrollToAnchor(elementId: string): void {
this.viewportScroller.scrollToAnchor(elementId);
}
}
We can call function from above reusable service from any component as :
//(In component.ts)
......
constructor(
private routerPathService: RouterPathService,
) {
this.routerPathService.scroll();
}
....
HTML component would like :
<a [routerLink]="['/my-route']" fragment="test">Testing</a>
And app-routing.module.ts should enable the anchoring as:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
.........
];
@NgModule({
imports: [RouterModule.forRoot(routes, {
anchorScrolling: 'enabled',
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
Upvotes: 2
Reputation: 354
From Angular 6.1 there is anchorScrolling
for the router:
Set this in app.module.ts
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled', // or 'top'
anchorScrolling: 'enabled',
scrollOffset: [0, 64] // [x, y] - adjust scroll offset
})
],
exports: [RouterModule]
html
<div id="test">
// contents goes here...
</div>
<a [routerLink]="['./']" fragment="test">Testing</a>
Import now the viewScroller which Angular v6 new feature (this might be not neccesary):
import { ViewportScroller } from '@angular/common';
constructor( private viewportScroller: ViewportScroller )
...
scrollToTest() {
this.viewportScroller.scrollToAnchor('test');
}
Upvotes: 11
Reputation: 21927
Based on @vsavkin workaround and taking advantage that fragments are provided as an observable (using "@angular/core": "^2.3.1"
):
class MyAppComponent implements OnInit{
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.fragment.subscribe(f => {
const element = document.querySelector("#" + f)
if (element) element.scrollIntoView()
})
}
}
Upvotes: 26
Reputation: 96
I can suggest to user ng2-page-scroll
install
npm install ng2-page-scroll --save
import in your app.module.ts
import {Ng2PageScrollModule} from 'ng2-page-scroll';
@NgModule({
imports: [
/* Other imports here */
Ng2PageScrollModule
]
})
export class AppModule {
}
test it in your html component
<a pageScroll href="#test">Testing</a>
<div id="test">
Upvotes: 2
Reputation: 41
I liked using this
scroll(container, target) {
let scrollTo = target.getBoundingClientRect().top;
$(container).animate({
scrollTop: `+=${scrollTo}`
}, 900);
}
then in HTML do something like
<div #container> <!-- Scrolling container -->
<button (click)="scroll(container, intro)">Go To Intro</button>
<!-- other content -->
<div #intro></div>
</div>
Upvotes: 0
Reputation: 649
I suppose scrolling isn't implemented with angular 2 yet. My solution to similar problem (scrolling to anchor on the same page) was to use ng2-page-scroll.
Upvotes: 3