I have an Angular 13 App that is supposed to be able to scroll to certain Elements on the page. As the view works with mat-tabs the only way to trigger a scolling effect is to use CDK's ScrollDispatcher in combination with the scrolled()-Observable.
I have a certain amount of buttons on top of each mat-tab followed by the actual page content. Each button is used to have the page scrolled to its particular target element, when it gets clicked.
Basically, this already works properly, with one exception. I have to scroll manually once after having clicked the mat-tab. Because only then I get the native element from scrollDispatcher.scrolled(). After this Observable has been fired for the first time I posess the native element I have to use for scolling and it then does its job perfectly. Each button click scrolls exactly to the point I expect.
But I don't want to have to scroll manually first. This is my problem.
How can I start scrolling with my buttons from scratch without having to manually scroll once?
I tried to get access to the native element in question befor the srolling event.
ngOnInit(): void {
const elements: HTMLCollectionOf<Element> = document.getElementsByClassName('scroll-container-style ng-star-inserted');
if (elements && elements.length === 1)
{
this.scrollingNativeElement = elements[0];
console.log(this.scrollingNativeElement);
}
}
This works, as I actually get the element. But it seems that it is not yet registered or so, because when I then trigger the scolling event via code, nothing happens.
My onClick()-method works as soon as I got the native element from CDK. But when I use it with the native element I got before from document, nothing happens when clicking my buttons and calling the scrollTo()-method.
public onClick(elementId: string): void
{
const element: HTMLElement = document.getElementById(elementId);
const boundingClientRect: DOMRect = element.getBoundingClientRect();
const x: number = 0;
const y: number = boundingClientRect.y - 110;
this.scrollingNativeElement.scrollTo(x, y);
}
And this is how I get access to CDK's scrolling element
private scrollingNativeElement: Element;
private subscription: Subscription = new Subscription();
constructor(
private scrollDispatcher: ScrollDispatcher
)
{ }
ngOnInit(): void
{
this.subscription.add(
this.scrollDispatcher.scrolled().subscribe((data: CdkScrollable): void =>
{
this.scrollingNativeElement = data.getElementRef().nativeElement;
})
);
}
As I said. As soon, as I once scroll manually, the oberservable fires and hands me exactly the same object I actually can access before via document. But only when getting it from CDK it reacts on scrolling events of my onClick()-method.
But which user would accept to have to scroll manually first befor the Scroll-To-Buttons work?
Does anybody know a way to get the native object working with scrollTo() from start?
Well, in the meantime, while I was waiting for an answer, I found it out myself.
This is how one gets access to the cdkScrollable native element in question without waiting for the observable of scrolled() to be fired.
I put this code in my ngOnInit() and now my buttons scoll to their target element without being forced to scroll manually first.
const containers:Map<CdkScrollable, Subscription> = this.scrollDispatcher.scrollContainers;
const cdkScrollable: CdkScrollable = <CdkScrollable>containers.keys().next().value;
if (cdkScrollable)
{
this.scrollingNativeElement = cdkScrollable.getElementRef().nativeElement;
}