@@ -22,11 +22,13 @@ import {
2222 booleanAttribute ,
2323 numberAttribute ,
2424 inject ,
25+ DestroyRef ,
2526} from '@angular/core' ;
26- import { Observable , Subject , merge } from 'rxjs' ;
27- import { startWith , switchMap , takeUntil } from 'rxjs/operators' ;
27+ import { Observable , merge } from 'rxjs' ;
28+ import { startWith , switchMap } from 'rxjs/operators' ;
2829import { MatChip , MatChipEvent } from './chip' ;
2930import { MatChipAction , MatChipContent } from './chip-action' ;
31+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
3032
3133/**
3234 * Basic container component for the MatChip component.
@@ -53,16 +55,14 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
5355 protected _elementRef = inject < ElementRef < HTMLElement > > ( ElementRef ) ;
5456 protected _changeDetectorRef = inject ( ChangeDetectorRef ) ;
5557 private _dir = inject ( Directionality , { optional : true } ) ;
58+ protected readonly _destroyRef = inject ( DestroyRef ) ;
5659
5760 /** Index of the last destroyed chip that had focus. */
5861 private _lastDestroyedFocusedChipIndex : number | null = null ;
5962
6063 /** Used to manage focus within the chip list. */
6164 protected _keyManager : FocusKeyManager < MatChipAction > ;
6265
63- /** Subject that emits when the component has been destroyed. */
64- protected _destroyed = new Subject < void > ( ) ;
65-
6666 /** Role to use if it hasn't been overwritten by the user. */
6767 protected _defaultRole = 'presentation' ;
6868
@@ -146,8 +146,6 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
146146 ngOnDestroy ( ) {
147147 this . _keyManager ?. destroy ( ) ;
148148 this . _chipActions . destroy ( ) ;
149- this . _destroyed . next ( ) ;
150- this . _destroyed . complete ( ) ;
151149 }
152150
153151 /** Checks whether any of the chips is focused. */
@@ -249,7 +247,7 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
249247
250248 // Keep the manager active index in sync so that navigation picks
251249 // up from the current chip if the user clicks into the list directly.
252- this . chipFocusChanges . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( { chip} ) => {
250+ this . chipFocusChanges . pipe ( takeUntilDestroyed ( this . _destroyRef ) ) . subscribe ( ( { chip} ) => {
253251 const action = chip . _getSourceAction ( document . activeElement as Element ) ;
254252
255253 if ( action ) {
@@ -258,7 +256,7 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
258256 } ) ;
259257
260258 this . _dir ?. change
261- . pipe ( takeUntil ( this . _destroyed ) )
259+ . pipe ( takeUntilDestroyed ( this . _destroyRef ) )
262260 . subscribe ( direction => this . _keyManager . withHorizontalOrientation ( direction ) ) ;
263261 }
264262
@@ -273,42 +271,46 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
273271
274272 /** Listens to changes in the chip set and syncs up the state of the individual chips. */
275273 private _trackChipSetChanges ( ) {
276- this . _chips . changes . pipe ( startWith ( null ) , takeUntil ( this . _destroyed ) ) . subscribe ( ( ) => {
277- if ( this . disabled ) {
278- // Since this happens after the content has been
279- // checked, we need to defer it to the next tick.
280- Promise . resolve ( ) . then ( ( ) => this . _syncChipsState ( ) ) ;
281- }
274+ this . _chips . changes
275+ . pipe ( startWith ( null ) , takeUntilDestroyed ( this . _destroyRef ) )
276+ . subscribe ( ( ) => {
277+ if ( this . disabled ) {
278+ // Since this happens after the content has been
279+ // checked, we need to defer it to the next tick.
280+ Promise . resolve ( ) . then ( ( ) => this . _syncChipsState ( ) ) ;
281+ }
282282
283- this . _redirectDestroyedChipFocus ( ) ;
284- } ) ;
283+ this . _redirectDestroyedChipFocus ( ) ;
284+ } ) ;
285285 }
286286
287287 /** Starts tracking the destroyed chips in order to capture the focused one. */
288288 private _trackDestroyedFocusedChip ( ) {
289- this . chipDestroyedChanges . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( event : MatChipEvent ) => {
290- // If the focused chip is destroyed, save its index so that we can move focus to the next
291- // chip. We only save the index here, rather than move the focus immediately, because we want
292- // to wait until the chip is removed from the chip list before focusing the next one. This
293- // allows us to keep focus on the same index if the chip gets swapped out.
294- const chipArray = this . _chips . toArray ( ) ;
295- const chipIndex = chipArray . indexOf ( event . chip ) ;
296- const hasFocus = event . chip . _hasFocus ( ) ;
297- const wasLastFocused =
298- event . chip . _hadFocusOnRemove &&
299- this . _keyManager . activeItem &&
300- event . chip . _getActions ( ) . includes ( this . _keyManager . activeItem ) ;
301-
302- // Note that depending on the timing, the chip might've already lost focus by the
303- // time we check this. We need the `wasLastFocused` as a fallback to detect such cases.
304- // In `wasLastFocused` we also need to ensure that the chip actually had focus when it was
305- // deleted so that we don't steal away the user's focus after they've moved on from the chip.
306- const shouldMoveFocus = hasFocus || wasLastFocused ;
307-
308- if ( this . _isValidIndex ( chipIndex ) && shouldMoveFocus ) {
309- this . _lastDestroyedFocusedChipIndex = chipIndex ;
310- }
311- } ) ;
289+ this . chipDestroyedChanges
290+ . pipe ( takeUntilDestroyed ( this . _destroyRef ) )
291+ . subscribe ( ( event : MatChipEvent ) => {
292+ // If the focused chip is destroyed, save its index so that we can move focus to the next
293+ // chip. We only save the index here, rather than move the focus immediately, because we want
294+ // to wait until the chip is removed from the chip list before focusing the next one. This
295+ // allows us to keep focus on the same index if the chip gets swapped out.
296+ const chipArray = this . _chips . toArray ( ) ;
297+ const chipIndex = chipArray . indexOf ( event . chip ) ;
298+ const hasFocus = event . chip . _hasFocus ( ) ;
299+ const wasLastFocused =
300+ event . chip . _hadFocusOnRemove &&
301+ this . _keyManager . activeItem &&
302+ event . chip . _getActions ( ) . includes ( this . _keyManager . activeItem ) ;
303+
304+ // Note that depending on the timing, the chip might've already lost focus by the
305+ // time we check this. We need the `wasLastFocused` as a fallback to detect such cases.
306+ // In `wasLastFocused` we also need to ensure that the chip actually had focus when it was
307+ // deleted so that we don't steal away the user's focus after they've moved on from the chip.
308+ const shouldMoveFocus = hasFocus || wasLastFocused ;
309+
310+ if ( this . _isValidIndex ( chipIndex ) && shouldMoveFocus ) {
311+ this . _lastDestroyedFocusedChipIndex = chipIndex ;
312+ }
313+ } ) ;
312314 }
313315
314316 /**
0 commit comments