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

Commit 7109a0d

Browse files
committed
build: enable strictPropertyInitialization
- fix related build errors - complete `this._destroyed` in `ngOnDestroy()` - replace use of deprecated `DomPortalHost` with `DomPortalOutlet`
1 parent c3509a9 commit 7109a0d

File tree

17 files changed

+106
-78
lines changed

17 files changed

+106
-78
lines changed

src/app/pages/component-category-list/component-category-list.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import {ActivatedRoute, Params, RouterModule} from '@angular/router';
55
import {DocumentationItems, SECTIONS} from '../../shared/documentation-items/documentation-items';
66
import {ComponentPageTitle} from '../page-title/page-title';
77
import {SvgViewerModule} from '../../shared/svg-viewer/svg-viewer';
8-
import {Observable, combineLatest, Subscription} from 'rxjs';
9-
8+
import {combineLatest, Observable, Subject} from 'rxjs';
9+
import {takeUntil} from 'rxjs/operators';
1010

1111
@Component({
1212
selector: 'app-component-category-list',
1313
templateUrl: './component-category-list.html',
1414
styleUrls: ['./component-category-list.scss']
1515
})
1616
export class ComponentCategoryList implements OnInit, OnDestroy {
17-
params: Observable<Params>;
18-
routeParamSubscription: Subscription;
19-
_categoryListSummary: string;
17+
params: Observable<Params> | undefined;
18+
private _destroyed = new Subject();
19+
_categoryListSummary: string | undefined;
2020

2121
constructor(public docItems: DocumentationItems,
2222
public _componentPageTitle: ComponentPageTitle,
@@ -29,7 +29,7 @@ export class ComponentCategoryList implements OnInit, OnDestroy {
2929
Object.assign);
3030

3131
// title on topbar navigation
32-
this.routeParamSubscription = this.params.subscribe(params => {
32+
this.params.pipe(takeUntil(this._destroyed)).subscribe(params => {
3333
const sectionName = params['section'];
3434
const section = SECTIONS[sectionName];
3535
this._componentPageTitle.title = section.name;
@@ -38,7 +38,8 @@ export class ComponentCategoryList implements OnInit, OnDestroy {
3838
}
3939

4040
ngOnDestroy() {
41-
this.routeParamSubscription.unsubscribe();
41+
this._destroyed.next();
42+
this._destroyed.complete();
4243
}
4344
}
4445

src/app/pages/component-list/component-list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {combineLatest} from 'rxjs';
1717
})
1818
export class ComponentList {
1919
category: DocCategory | undefined;
20-
section: string;
20+
section: string | undefined;
2121

2222
constructor(public docItems: DocumentationItems,
2323
private _componentPageTitle: ComponentPageTitle,

src/app/pages/component-sidenav/component-sidenav.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import {
2-
Component, Input, NgZone, ViewEncapsulation, ViewChild, OnInit, NgModule, OnDestroy
2+
Component,
3+
Input,
4+
NgModule,
5+
NgZone,
6+
OnChanges,
7+
OnDestroy,
8+
OnInit,
9+
SimpleChanges,
10+
ViewChild,
11+
ViewEncapsulation
312
} from '@angular/core';
413
import {DocumentationItems} from '../../shared/documentation-items/documentation-items';
514
import {MatIconModule} from '@angular/material/icon';
@@ -9,9 +18,9 @@ import {ActivatedRoute, Params, Router, RouterModule} from '@angular/router';
918
import {CommonModule} from '@angular/common';
1019
import {ComponentHeaderModule} from '../component-page-header/component-page-header';
1120
import {FooterModule} from '../../shared/footer/footer';
12-
import {Observable, Subject, combineLatest} from 'rxjs';
13-
import {switchMap, takeUntil, startWith, map} from 'rxjs/operators';
14-
import {trigger, animate, state, style, transition} from '@angular/animations';
21+
import {combineLatest, Observable, Subject} from 'rxjs';
22+
import {map, takeUntil} from 'rxjs/operators';
23+
import {animate, state, style, transition, trigger} from '@angular/animations';
1524
import {CdkAccordionModule} from '@angular/cdk/accordion';
1625
import {BreakpointObserver} from '@angular/cdk/layout';
1726

@@ -24,8 +33,8 @@ const SMALL_WIDTH_BREAKPOINT = 720;
2433
encapsulation: ViewEncapsulation.None,
2534
})
2635
export class ComponentSidenav implements OnInit {
27-
@ViewChild(MatSidenav) sidenav: MatSidenav;
28-
params: Observable<Params>;
36+
@ViewChild(MatSidenav) sidenav!: MatSidenav;
37+
params: Observable<Params> | undefined;
2938
isScreenSmall: Observable<boolean>;
3039

3140
constructor(public docItems: DocumentationItems,
@@ -55,26 +64,35 @@ export class ComponentSidenav implements OnInit {
5564
]),
5665
],
5766
})
58-
export class ComponentNav implements OnInit, OnDestroy {
59-
60-
@Input() params: Observable<Params>;
67+
export class ComponentNav implements OnInit, OnDestroy, OnChanges {
68+
@Input() params: Observable<Params> | undefined;
6169
expansions: {[key: string]: boolean} = {};
62-
private _onDestroy = new Subject<void>();
70+
private _destroyed = new Subject();
6371

64-
constructor(public docItems: DocumentationItems,
65-
private _router: Router) { }
72+
constructor(public docItems: DocumentationItems, private _router: Router) {}
6673

6774
ngOnInit() {
68-
this._router.events.pipe(
69-
startWith(null),
70-
switchMap(() => this.params),
71-
takeUntil(this._onDestroy)
72-
).subscribe(p => this.setExpansions(p));
75+
if (this.params) {
76+
this.subscribeToParamChanges(this.params);
77+
}
78+
}
79+
80+
ngOnChanges(changes: SimpleChanges): void {
81+
if (changes.params && changes.params.currentValue &&
82+
(changes.params.currentValue != changes.params.previousValue)) {
83+
this.subscribeToParamChanges(
84+
(changes.params.currentValue as Observable<Params>));
85+
}
86+
}
87+
88+
subscribeToParamChanges(newParams: Observable<Params>) {
89+
newParams.pipe(takeUntil(this._destroyed))
90+
.subscribe(params => this.setExpansions(params));
7391
}
7492

7593
ngOnDestroy() {
76-
this._onDestroy.next();
77-
this._onDestroy.complete();
94+
this._destroyed.next();
95+
this._destroyed.complete();
7896
}
7997

8098
/** Set the expansions based on the route url */
@@ -113,7 +131,6 @@ export class ComponentNav implements OnInit, OnDestroy {
113131
getExpanded(category: string): boolean {
114132
return this.expansions[category] === undefined ? true : this.expansions[category];
115133
}
116-
117134
}
118135

119136

src/app/pages/component-viewer/component-viewer.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ export class ComponentViewer implements OnDestroy {
3131
sections: Set<string> = new Set(['overview', 'api']);
3232
private _destroyed = new Subject();
3333

34-
constructor(_route: ActivatedRoute,
35-
private router: Router,
34+
constructor(_route: ActivatedRoute, private router: Router,
3635
public _componentPageTitle: ComponentPageTitle,
37-
public docItems: DocumentationItems,
38-
) {
36+
public docItems: DocumentationItems) {
3937
let routeAndParentParams = [_route.params];
4038
if (_route.parent) {
4139
routeAndParentParams.push(_route.parent.params);
@@ -73,20 +71,18 @@ export class ComponentViewer implements OnDestroy {
7371
*/
7472
@Directive()
7573
export class ComponentBaseView implements OnInit, OnDestroy {
76-
@ViewChild('initialFocusTarget') focusTarget: ElementRef;
77-
@ViewChild('toc') tableOfContents: TableOfContents;
78-
74+
@ViewChild('initialFocusTarget') focusTarget!: ElementRef;
75+
@ViewChild('toc') tableOfContents!: TableOfContents;
7976
showToc: Observable<boolean>;
80-
81-
destroyed = new Subject<void>();
77+
private _destroyed = new Subject();
8278

8379
constructor(public componentViewer: ComponentViewer, breakpointObserver: BreakpointObserver) {
8480
this.showToc = breakpointObserver.observe('(max-width: 1200px)')
8581
.pipe(map(result => !result.matches));
8682
}
8783

8884
ngOnInit() {
89-
this.componentViewer.componentDocItem.pipe(takeUntil(this.destroyed)).subscribe(() => {
85+
this.componentViewer.componentDocItem.pipe(takeUntil(this._destroyed)).subscribe(() => {
9086
// 100ms timeout is used to allow the page to settle before moving focus for screen readers.
9187
setTimeout(() => this.focusTarget.nativeElement.focus({preventScroll: true}), 100);
9288
if (this.tableOfContents) {
@@ -96,7 +92,8 @@ export class ComponentBaseView implements OnInit, OnDestroy {
9692
}
9793

9894
ngOnDestroy() {
99-
this.destroyed.next();
95+
this._destroyed.next();
96+
this._destroyed.complete();
10097
}
10198

10299
updateTableOfContents(sectionName: string, docViewerContent: HTMLElement) {

src/app/shared/copier/copier.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {Injectable} from '@angular/core';
1111
@Injectable()
1212
export class CopierService {
1313

14-
private textarea: HTMLTextAreaElement;
14+
private textarea: HTMLTextAreaElement | undefined;
1515

1616
/** Copy the text value to the clipboard. */
1717
copyText(text: string): boolean {

src/app/shared/doc-viewer/doc-viewer-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {DocViewer} from './doc-viewer';
22
import {ExampleViewer} from '../example-viewer/example-viewer';
3-
import {StackBlitzButtonModule} from '../stack-blitz/stack-blitz-button';
3+
import {StackBlitzButtonModule} from '../stack-blitz';
44
import {MatButtonModule} from '@angular/material/button';
55
import {MatIconModule} from '@angular/material/icon';
66
import {MatSnackBarModule} from '@angular/material/snack-bar';

src/app/shared/doc-viewer/doc-viewer.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {ComponentPortal, DomPortalHost} from '@angular/cdk/portal';
1+
import {ComponentPortal, DomPortalOutlet} from '@angular/cdk/portal';
22
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
33
import {DomSanitizer} from '@angular/platform-browser';
44
import {
@@ -25,10 +25,9 @@ import {HeaderLink} from './header-link';
2525
template: 'Loading document...',
2626
})
2727
export class DocViewer implements OnDestroy {
28-
private _portalHosts: DomPortalHost[] = [];
29-
private _documentFetchSubscription: Subscription;
30-
31-
@Input() name: string;
28+
private _portalHosts: DomPortalOutlet[] = [];
29+
private _documentFetchSubscription!: Subscription;
30+
@Input() name: string | undefined;
3231

3332
/** The URL of the document to display. */
3433
@Input()
@@ -107,7 +106,7 @@ export class DocViewer implements OnDestroy {
107106

108107
Array.prototype.slice.call(exampleElements).forEach((element: Element) => {
109108
let example = element.getAttribute(componentName);
110-
let portalHost = new DomPortalHost(
109+
let portalHost = new DomPortalOutlet(
111110
element, this._componentFactoryResolver, this._appRef, this._injector);
112111
let examplePortal = new ComponentPortal(componentClass, this._viewContainerRef);
113112
let exampleViewer = portalHost.attach(examplePortal);

src/app/shared/doc-viewer/header-link.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class HeaderLink {
3333
* Id of the anchor element. Note that is uses "example" because we instantiate the
3434
* header link components through the ComponentPortal.
3535
*/
36-
@Input() example: string;
36+
@Input() example: string | undefined;
3737

3838
/** Base URL that is used to build an absolute fragment URL. */
3939
private _baseUrl: string;

src/app/shared/example-viewer/example-viewer.html

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,31 @@
55
<button mat-icon-button type="button" (click)="toggleSourceView()"
66
[matTooltip]="'View source'">
77
<mat-icon>
8-
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fit="" preserveAspectRatio="xMidYMid meet" focusable="false">
8+
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24"
9+
fit="" preserveAspectRatio="xMidYMid meet" focusable="false">
910
<path fill="none" d="M0 0h24v24H0V0z"></path>
10-
<path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"></path>
11+
<path
12+
d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z">
13+
</path>
1114
</svg>
1215
</mat-icon>
1316
</button>
1417

15-
<stack-blitz-button [example]="example"></stack-blitz-button>
16-
</div>
18+
<stack-blitz-button [example]="example"></stack-blitz-button>
19+
</div>
1720

1821
<div class="docs-example-viewer-source" *ngIf="showSource">
19-
<mat-tab-group>
22+
<mat-tab-group *ngIf="exampleTabs">
2023
<mat-tab *ngFor="let tabName of _getExampleTabNames()" [label]="tabName">
2124
<div class="docs-example-source-wrapper">
2225
<button mat-icon-button type="button" class="docs-example-source-copy"
2326
title="Copy example source" aria-label="Copy example source to clipboard"
2427
(click)="copySource(viewer.textContent)">
2528
<mat-icon>content_copy</mat-icon>
2629
</button>
27-
<pre class="docs-example-source"><doc-viewer
28-
#viewer [documentUrl]="exampleTabs[tabName]"></doc-viewer></pre>
30+
<pre class="docs-example-source">
31+
<doc-viewer #viewer [documentUrl]="exampleTabs[tabName]"></doc-viewer>
32+
</pre>
2933
</div>
3034
</mat-tab>
3135
</mat-tab-group>

src/app/shared/example-viewer/example-viewer.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('ExampleViewer', () => {
7878

7979
extensions.forEach(extension => {
8080
const expected = `${basePath}${exampleKey}-example-${extension}.html`;
81-
const actual = component.exampleTabs[extension.toUpperCase()];
81+
const actual = component.exampleTabs![extension.toUpperCase()];
8282

8383
expect(actual).toEqual(expected);
8484
});

src/app/shared/example-viewer/example-viewer.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ const fileExtensionRegex = /(.*)\.(\w+)/;
1515
})
1616
export class ExampleViewer {
1717
/** Component portal for the currently displayed example. */
18-
selectedPortal: ComponentPortal<any>;
18+
selectedPortal: ComponentPortal<any> | undefined;
1919

2020
/** Map of example files that should be displayed in the view-source tab. */
21-
exampleTabs: {[tabName: string]: string};
21+
exampleTabs: {[tabName: string]: string} | undefined;
2222

2323
/** Data for the currently selected example. */
24-
exampleData: LiveExample;
24+
exampleData: LiveExample | undefined;
2525

2626
/** Whether the source for the example is being displayed. */
2727
showSource = false;
2828

2929
/** String key of the currently displayed example. */
3030
@Input()
3131
get example() { return this._example; }
32-
set example(exampleName: string) {
32+
set example(exampleName: string | undefined) {
3333
if (exampleName && EXAMPLE_COMPONENTS[exampleName]) {
3434
this._example = exampleName;
3535
this.exampleData = EXAMPLE_COMPONENTS[exampleName];
@@ -39,7 +39,7 @@ export class ExampleViewer {
3939
console.error(`Could not find example: ${exampleName}`);
4040
}
4141
}
42-
private _example: string;
42+
private _example: string | undefined;
4343

4444
constructor(private snackbar: MatSnackBar, private copier: CopierService) {}
4545

@@ -55,8 +55,8 @@ export class ExampleViewer {
5555
}
5656
}
5757

58-
_getExampleTabNames() {
59-
return Object.keys(this.exampleTabs);
58+
_getExampleTabNames(): string[] {
59+
return this.exampleTabs ? Object.keys(this.exampleTabs) : [];
6060
}
6161

6262
private resolveHighlightedExampleFile(fileName: string) {
@@ -70,13 +70,17 @@ export class ExampleViewer {
7070
CSS: this.resolveHighlightedExampleFile(`${this.example}-example-css.html`),
7171
};
7272

73-
const additionalFiles = this.exampleData.additionalFiles || [];
73+
const additionalFiles = this.exampleData && this.exampleData.additionalFiles
74+
? this.exampleData.additionalFiles
75+
: [];
7476

7577
additionalFiles.forEach(fileName => {
7678
// Since the additional files refer to the original file name, we need to transform
7779
// the file name to match the highlighted HTML file that displays the source.
7880
const fileSourceName = fileName.replace(fileExtensionRegex, '$1-$2.html');
79-
this.exampleTabs[fileName] = this.resolveHighlightedExampleFile(fileSourceName);
81+
if (this.exampleTabs) {
82+
this.exampleTabs[fileName] = this.resolveHighlightedExampleFile(fileSourceName);
83+
}
8084
});
8185
}
8286
}

src/app/shared/ga/ga.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {environment} from '../../../environments/environment';
1010
*/
1111
export class GaService {
1212

13-
private previousUrl: string;
13+
private previousUrl: string | undefined;
1414

1515
constructor() {
1616
this.ga('create', environment['matGaId'] , 'auto', 'mat');

0 commit comments

Comments
 (0)