Skip to content

Commit 2b85d59

Browse files
authored
docs: use takeUntilDestroyed for cleanup instead of manual subscription handling (angular#32023)
1 parent 6869909 commit 2b85d59

File tree

2 files changed

+31
-50
lines changed

2 files changed

+31
-50
lines changed

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

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,13 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {
10-
Component,
11-
OnDestroy,
12-
OnInit,
13-
ViewEncapsulation,
14-
forwardRef,
15-
inject,
16-
viewChild,
17-
} from '@angular/core';
9+
import {Component, ViewEncapsulation, forwardRef, inject, viewChild} from '@angular/core';
1810
import {BreakpointObserver} from '@angular/cdk/layout';
1911
import {AsyncPipe} from '@angular/common';
2012
import {MatListItem, MatNavList} from '@angular/material/list';
2113
import {MatSidenav, MatSidenavContainer} from '@angular/material/sidenav';
2214
import {ActivatedRoute, Routes, RouterOutlet, RouterLinkActive, RouterLink} from '@angular/router';
23-
import {Observable, of, Subscription} from 'rxjs';
15+
import {Observable, of} from 'rxjs';
2416
import {map, switchMap} from 'rxjs/operators';
2517

2618
import {DocumentationItems} from '../../shared/documentation-items/documentation-items';
@@ -37,6 +29,7 @@ import {
3729
ComponentViewer,
3830
} from '../component-viewer/component-viewer';
3931
import {ComponentStyling} from '../component-viewer/component-styling';
32+
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
4033

4134
// These constants are used by the ComponentSidenav for orchestrating the MatSidenav in a responsive
4235
// way. This includes hiding the sidenav, defaulting it to open, changing the mode from over to
@@ -63,14 +56,13 @@ const SMALL_WIDTH_BREAKPOINT = 959;
6356
AsyncPipe,
6457
],
6558
})
66-
export class ComponentSidenav implements OnInit, OnDestroy {
59+
export class ComponentSidenav {
6760
docItems = inject(DocumentationItems);
6861
private _navigationFocusService = inject(NavigationFocusService);
6962

7063
readonly sidenav = viewChild(MatSidenav);
7164
isExtraScreenSmall: Observable<boolean>;
7265
isScreenSmall: Observable<boolean>;
73-
private _subscriptions = new Subscription();
7466

7567
constructor() {
7668
const breakpoints = inject(BreakpointObserver);
@@ -81,23 +73,19 @@ export class ComponentSidenav implements OnInit, OnDestroy {
8173
this.isScreenSmall = breakpoints
8274
.observe(`(max-width: ${SMALL_WIDTH_BREAKPOINT}px)`)
8375
.pipe(map(breakpoint => breakpoint.matches));
84-
}
85-
86-
ngOnInit() {
87-
this._subscriptions.add(
88-
this._navigationFocusService.navigationEndEvents
89-
.pipe(map(() => this.isScreenSmall))
90-
.subscribe(shouldCloseSideNav => {
91-
const sidenav = this.sidenav();
92-
if (shouldCloseSideNav && sidenav) {
93-
sidenav.close();
94-
}
95-
}),
96-
);
97-
}
9876

99-
ngOnDestroy() {
100-
this._subscriptions.unsubscribe();
77+
// Close the sidenav on navigation when the screen is small.
78+
this._navigationFocusService.navigationEndEvents
79+
.pipe(
80+
takeUntilDestroyed(),
81+
map(() => this.isScreenSmall),
82+
)
83+
.subscribe(shouldCloseSideNav => {
84+
const sidenav = this.sidenav();
85+
if (shouldCloseSideNav && sidenav) {
86+
sidenav.close();
87+
}
88+
});
10189
}
10290

10391
toggleSidenav(): void {

docs/src/app/shared/navigation-focus/navigation-focus.service.ts

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {Injectable, OnDestroy, inject} from '@angular/core';
9+
import {Injectable, inject} from '@angular/core';
1010
import {Event, NavigationEnd, Router} from '@angular/router';
1111
import {filter, skip} from 'rxjs/operators';
12-
import {Subscription} from 'rxjs';
12+
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
1313

1414
@Injectable({
1515
providedIn: 'root',
1616
})
17-
export class NavigationFocusService implements OnDestroy {
17+
export class NavigationFocusService {
1818
private _router = inject(Router);
19-
private _subscriptions = new Subscription();
2019
private _navigationFocusRequests: HTMLElement[] = [];
2120
private _skipLinkFocusRequests: HTMLElement[] = [];
2221
private _skipLinkHref: string | null | undefined;
@@ -27,24 +26,18 @@ export class NavigationFocusService implements OnDestroy {
2726
readonly softNavigations = this.navigationEndEvents.pipe(skip(1));
2827

2928
constructor() {
30-
this._subscriptions.add(
31-
this.softNavigations.subscribe(() => {
32-
// focus if url does not have fragment
33-
if (!this._router.url.split('#')[1]) {
34-
setTimeout(() => {
35-
if (this._navigationFocusRequests.length) {
36-
this._navigationFocusRequests[this._navigationFocusRequests.length - 1].focus({
37-
preventScroll: true,
38-
});
39-
}
40-
}, 100);
41-
}
42-
}),
43-
);
44-
}
45-
46-
ngOnDestroy() {
47-
this._subscriptions.unsubscribe();
29+
this.softNavigations.pipe(takeUntilDestroyed()).subscribe(() => {
30+
// focus if url does not have fragment
31+
if (!this._router.url.split('#')[1]) {
32+
setTimeout(() => {
33+
if (this._navigationFocusRequests.length) {
34+
this._navigationFocusRequests[this._navigationFocusRequests.length - 1].focus({
35+
preventScroll: true,
36+
});
37+
}
38+
}, 100);
39+
}
40+
});
4841
}
4942

5043
requestFocusOnNavigation(el: HTMLElement) {

0 commit comments

Comments
 (0)