I have a main page with couple of sections. Each section can be reached by typing its fragment name on the url (Ex. www.website.com/#introduction - will open the homepage and scroll to the introduction section automatically). In order to do that, I need to fetch the section’s container element and run .scrollIntoView() function on it.
What I have done:
- List item I have created a store (ngrx) which stores the ElementRef(s) of the sections.
- In each section component (located in HomeComponent - parent of the sections), I put a
@ViewChild()pointing on the element.@ViewChild(‘container’, { static: true }) private container: ElementRef; - Then on
ngAfterViewInit()of this section component, I putStore.dispatch()which stores my ElementRef on the store.
this.store.dispatch(new HomeActions.SetElementRef({
linkName: COMP_LINK_NAME,
elementRef: this.container
}));
Then, in HomeComponent, I listen to the sectionsRef store this.store.select('sectionRefs').
Filtered it if its undefined (as it is the default of the store = default statement is empty).
this.sectionRefs$ = this.store.select('sectionRefs').pipe(
map((data: { sectionRefs: SectionReference[] }) => data.sectionRefs), // transform to a more convenient object
tap((sectionRefs: SectionReference[]) => this.sectionRefs = sectionRefs), // Updates the sectionRefs array regardless the completion of it (filter below)
filter((sectionRefs: SectionReference[]) => { // No emission until sectionRefs Element Refs are completed
return sectionRefs.find((sectionRef: SectionReference) => {
return (
sectionRef.element === undefined ||
sectionRef.element === null ||
sectionRef.element.nativeElement.offsetHeight === 0 && sectionRef.element.nativeElement.offsetWidth === 0
);
}) === undefined // Means that no incompleted sectionRef was found
}),
distinctUntilChanged(
(prev: SectionReference[], next: SectionReference[]) => JSON.stringify(prev) === JSON.stringify(next)
),
first()
);
- HomeCompoent: And eventually I listened to the ActivatedRoute.fragment, to check which ElementRef is relevant for the scrolling.
- HomeComponent: Activate .scrollIntoView() on the relevant ElementRef.
The issue is that I do it when the page is loaded so the ElementRef.nativeElement.scrollIntoView() is scrolling to incorrect place.
I checked to see the offsetHeight retrieved (ElementRef.nativeElement.offsetHeight) and it was also incorrect.
So In each section Component I wrapped the Store.dispatch() action with setTimeout()
setTimeout(() => {
this.store.dispatch(new HomeActions.SetElementRef({
linkName: COMP_LINK_NAME,
elementRef: this.container
}));
}, 150);
And it works! But it is looking like a very bad practice to do this work around.
Is there any other solution?