Skip to content
This repository was archived by the owner on Dec 18, 2024. It is now read-only.

Commit 0cbecaf

Browse files
committed
Use scroll dispatcher to respond to scroll events instead of manually subscribing to events on container
- Remove links as an input - Calculate container from scrollable event instead of using input
1 parent b36c688 commit 0cbecaf

File tree

6 files changed

+49
-41
lines changed

6 files changed

+49
-41
lines changed

src/app/pages/component-viewer/component-api.html

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,4 @@
55
documentUrl="/assets/documents/api/{{componentViewer.componentDocItem.packageName}}-{{componentViewer.componentDocItem.id}}.html"
66
class="docs-component-view-text-content docs-component-api"
77
(contentLoaded)="toc.updateScrollPosition()"></doc-viewer>
8-
<table-of-contents #toc
9-
headerSelectors=".docs-api-h3,.docs-api-h4"
10-
container=".mat-drawer-content"></table-of-contents>
8+
<table-of-contents #toc headerSelectors=".docs-api-h3,.docs-api-h4"></table-of-contents>

src/app/pages/component-viewer/component-overview.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
class="docs-component-view-text-content docs-component-overview"
77
(contentLoaded)="toc.updateScrollPosition()">
88
</doc-viewer>
9-
<table-of-contents #toc container=".mat-drawer-content"></table-of-contents>
9+
<table-of-contents #toc></table-of-contents>

src/app/shared/table-of-contents/table-of-contents.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<div *ngIf="links?.length" class="docs-toc-container">
1+
<div *ngIf="_links?.length" class="docs-toc-container">
22
<div class="docs-toc-heading">Contents</div>
33
<nav>
44
<a [href]="_rootUrl + '#' + link.id"
5-
*ngFor="let link of links; let i = index"
5+
*ngFor="let link of _links; let i = index"
66
class="docs-level-{{link.type}} docs-link"
77
[class.docs-active]="_activeLinkIndex === i">
88
{{link.name}}

src/app/shared/table-of-contents/table-of-contents.module.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {CommonModule} from '@angular/common';
2+
import {ScrollDispatchModule} from '@angular/cdk/scrolling';
23
import {NgModule} from '@angular/core';
34
import {TableOfContents} from './table-of-contents';
45
import {RouterModule} from '@angular/router';
56

67
@NgModule({
7-
imports: [CommonModule, RouterModule],
8+
imports: [CommonModule, RouterModule, ScrollDispatchModule],
89
declarations: [TableOfContents],
910
exports: [TableOfContents],
1011
entryComponents: [TableOfContents],

src/app/shared/table-of-contents/table-of-contents.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('TableOfContents', () => {
3939
});
4040

4141
it('should have header and links', () => {
42-
component.links = [
42+
component._links = [
4343
{
4444
type: 'h2',
4545
id: 'test',

src/app/shared/table-of-contents/table-of-contents.ts

+42-33
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import {Component, ElementRef, Inject, Input, OnInit} from '@angular/core';
1+
import {Component, ElementRef, Inject, Input, NgZone, OnDestroy, OnInit} from '@angular/core';
22
import {DOCUMENT} from '@angular/platform-browser';
33
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
4-
import 'rxjs/add/observable/fromEvent';
5-
import 'rxjs/add/operator/debounceTime';
6-
import 'rxjs/add/operator/takeUntil';
7-
import {Observable} from 'rxjs/Observable';
4+
import {ScrollDispatcher, CdkScrollable} from '@angular/cdk/scrolling';
85
import {Subject} from 'rxjs/Subject';
6+
import 'rxjs/add/operator/filter';
7+
import 'rxjs/add/operator/takeUntil';
98

109
interface Link {
1110
/* id of the section*/
@@ -26,12 +25,11 @@ interface Link {
2625
styleUrls: ['./table-of-contents.scss'],
2726
templateUrl: './table-of-contents.html',
2827
})
29-
export class TableOfContents implements OnInit {
28+
export class TableOfContents implements OnDestroy, OnInit {
3029

31-
@Input() links: Link[] = [];
32-
@Input() container: string;
3330
@Input() headerSelectors = '.docs-markdown-h3,.docs-markdown-h4';
3431

32+
_links: Link[] = [];
3533
_activeLinkIndex: number;
3634
_rootUrl: string;
3735
private _scrollContainer: any;
@@ -41,44 +39,49 @@ export class TableOfContents implements OnInit {
4139
constructor(private _router: Router,
4240
private _route: ActivatedRoute,
4341
private _element: ElementRef,
42+
private _scrollDispatcher: ScrollDispatcher,
43+
private _ngZone: NgZone,
4444
@Inject(DOCUMENT) private _document: Document) {
4545

46-
this._router.events.takeUntil(this._destroyed).subscribe((event) => {
47-
if (event instanceof NavigationEnd) {
46+
// Create new links and save root url at the end of navigation
47+
this._router.events
48+
.filter(event => event instanceof NavigationEnd)
49+
.takeUntil(this._destroyed)
50+
.subscribe(event => {
4851
const rootUrl = _router.url.split('#')[0];
4952
if (rootUrl !== this._rootUrl) {
50-
this.links = this.createLinks();
53+
this._links = this.createLinks();
5154
this._rootUrl = rootUrl;
5255
}
53-
}
54-
});
55-
56-
this._route.fragment.takeUntil(this._destroyed).subscribe(fragment => {
57-
this._urlFragment = fragment;
58-
this.scrollFragmentIntoView();
59-
});
56+
});
57+
58+
// Scroll to section when the fragment changes
59+
this._route.fragment
60+
.takeUntil(this._destroyed)
61+
.subscribe(fragment => {
62+
this._urlFragment = fragment;
63+
this.scrollFragmentIntoView();
64+
});
6065
}
6166

62-
ngOnInit(): void {
63-
// On init, the sidenav content element doesn't yet exist, so it's not possible
64-
// to subscribe to its scroll event until next tick (when it does exist).
65-
Promise.resolve().then(() => {
66-
this._scrollContainer = this.container ?
67-
this._document.querySelectorAll(this.container)[0] : window;
68-
69-
Observable.fromEvent(this._scrollContainer, 'scroll')
70-
.takeUntil(this._destroyed)
71-
.debounceTime(10)
72-
.subscribe(() => this.setActiveLink());
73-
});
67+
ngOnInit() {
68+
// Update active link after scroll events
69+
this._scrollDispatcher.scrolled()
70+
.takeUntil(this._destroyed)
71+
.subscribe(scrollable =>
72+
this._ngZone.run(() => {
73+
this.updateScrollContainer(scrollable);
74+
this.setActiveLink();
75+
}));
7476
}
7577

7678
ngOnDestroy(): void {
7779
this._destroyed.next();
80+
this._destroyed.complete();
7881
}
7982

8083
updateScrollPosition(): void {
81-
this.links = this.createLinks();
84+
this._links = this.createLinks();
8285
this.scrollFragmentIntoView();
8386
}
8487

@@ -109,8 +112,8 @@ export class TableOfContents implements OnInit {
109112
}
110113

111114
private setActiveLink(): void {
112-
this._activeLinkIndex = this.links
113-
.findIndex((link, i) => this.isLinkActive(link, this.links[i + 1]));
115+
this._activeLinkIndex = this._links
116+
.findIndex((link, i) => this.isLinkActive(link, this._links[i + 1]));
114117
}
115118

116119
private isLinkActive(currentLink: any, nextLink: any): boolean {
@@ -134,4 +137,10 @@ export class TableOfContents implements OnInit {
134137
return 0;
135138
}
136139

140+
private updateScrollContainer(scrollable: CdkScrollable | void): void {
141+
this._scrollContainer = scrollable ?
142+
scrollable.getElementRef().nativeElement :
143+
window;
144+
}
145+
137146
}

0 commit comments

Comments
 (0)