@@ -10,7 +10,6 @@ import {FocusableOption, FocusKeyManager} from '@angular/cdk/a11y';
1010import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
1111import { SelectionModel } from '@angular/cdk/collections' ;
1212import { SPACE } from '@angular/cdk/keycodes' ;
13- import { RxChain , startWith , switchMap } from '@angular/cdk/rxjs' ;
1413import {
1514 AfterContentInit ,
1615 ChangeDetectionStrategy ,
@@ -38,8 +37,6 @@ import {
3837 mixinDisabled ,
3938 mixinDisableRipple ,
4039} from '@angular/material/core' ;
41- import { merge } from 'rxjs/observable/merge' ;
42- import { Subscription } from 'rxjs/Subscription' ;
4340
4441
4542/** @docs -private */
@@ -55,8 +52,6 @@ export interface MatSelectionListOptionEvent {
5552 option : MatListOption ;
5653}
5754
58- const FOCUSED_STYLE : string = 'mat-list-item-focus' ;
59-
6055/**
6156 * Component for list-options of selection-list. Each list-option can automatically
6257 * generate a checkbox and can put current item into the selectionModel of selection-list
@@ -70,10 +65,11 @@ const FOCUSED_STYLE: string = 'mat-list-item-focus';
7065 'role' : 'option' ,
7166 'class' : 'mat-list-item mat-list-option' ,
7267 '(focus)' : '_handleFocus()' ,
73- '(blur)' : '_handleBlur() ' ,
68+ '(blur)' : '_hasFocus = false ' ,
7469 '(click)' : '_handleClick()' ,
7570 'tabindex' : '-1' ,
7671 '[class.mat-list-item-disabled]' : 'disabled' ,
72+ '[class.mat-list-item-focus]' : '_hasFocus' ,
7773 '[attr.aria-selected]' : 'selected.toString()' ,
7874 '[attr.aria-disabled]' : 'disabled.toString()' ,
7975 } ,
@@ -109,18 +105,12 @@ export class MatListOption extends _MatListOptionMixinBase
109105 get selected ( ) { return this . _selected ; }
110106 set selected ( value : boolean ) { this . _selected = coerceBooleanProperty ( value ) ; }
111107
112- /** Emitted when the option is focused. */
113- onFocus = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
114-
115108 /** Emitted when the option is selected. */
116109 @Output ( ) selectChange = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
117110
118111 /** Emitted when the option is deselected. */
119112 @Output ( ) deselected = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
120113
121- /** Emitted when the option is destroyed. */
122- @Output ( ) destroyed = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
123-
124114 constructor ( private _renderer : Renderer2 ,
125115 private _element : ElementRef ,
126116 private _changeDetector : ChangeDetectorRef ,
@@ -144,7 +134,7 @@ export class MatListOption extends _MatListOptionMixinBase
144134 }
145135
146136 ngOnDestroy ( ) : void {
147- this . destroyed . emit ( { option : this } ) ;
137+ this . selectionList . _removeOptionFromList ( this ) ;
148138 }
149139
150140 /** Toggles the selection state of the option. */
@@ -157,7 +147,6 @@ export class MatListOption extends _MatListOptionMixinBase
157147 /** Allows for programmatic focusing of the option. */
158148 focus ( ) : void {
159149 this . _element . nativeElement . focus ( ) ;
160- this . onFocus . emit ( { option : this } ) ;
161150 }
162151
163152 /** Whether this list item should show a ripple effect when clicked. */
@@ -173,11 +162,7 @@ export class MatListOption extends _MatListOptionMixinBase
173162
174163 _handleFocus ( ) {
175164 this . _hasFocus = true ;
176- this . _renderer . addClass ( this . _element . nativeElement , FOCUSED_STYLE ) ;
177- }
178-
179- _handleBlur ( ) {
180- this . _renderer . removeClass ( this . _element . nativeElement , FOCUSED_STYLE ) ;
165+ this . selectionList . _setFocusedOption ( this ) ;
181166 }
182167
183168 /** Retrieves the DOM element of the component host. */
@@ -208,17 +193,11 @@ export class MatListOption extends _MatListOptionMixinBase
208193 changeDetection : ChangeDetectionStrategy . OnPush
209194} )
210195export class MatSelectionList extends _MatSelectionListMixinBase
211- implements FocusableOption , CanDisable , CanDisableRipple , AfterContentInit , OnDestroy {
196+ implements FocusableOption , CanDisable , CanDisableRipple , AfterContentInit {
212197
213198 /** Tab index for the selection-list. */
214199 _tabIndex = 0 ;
215200
216- /** Subscription to all list options' onFocus events */
217- private _optionFocusSubscription = Subscription . EMPTY ;
218-
219- /** Subscription to all list options' destroy events */
220- private _optionDestroyStream = Subscription . EMPTY ;
221-
222201 /** The FocusKeyManager which handles focus. */
223202 _keyManager : FocusKeyManager < MatListOption > ;
224203
@@ -238,14 +217,6 @@ export class MatSelectionList extends _MatSelectionListMixinBase
238217 if ( this . disabled ) {
239218 this . _tabIndex = - 1 ;
240219 }
241-
242- this . _optionFocusSubscription = this . _onFocusSubscription ( ) ;
243- this . _optionDestroyStream = this . _onDestroySubscription ( ) ;
244- }
245-
246- ngOnDestroy ( ) : void {
247- this . _optionDestroyStream . unsubscribe ( ) ;
248- this . _optionFocusSubscription . unsubscribe ( ) ;
249220 }
250221
251222 /** Focus the selection-list. */
@@ -271,36 +242,23 @@ export class MatSelectionList extends _MatSelectionListMixinBase
271242 } ) ;
272243 }
273244
274- /** Map all the options' destroy event subscriptions and merge them into one stream. */
275- private _onDestroySubscription ( ) : Subscription {
276- return RxChain . from ( this . options . changes )
277- . call ( startWith , this . options )
278- . call ( switchMap , ( options : MatListOption [ ] ) => {
279- return merge ( ...options . map ( option => option . destroyed ) ) ;
280- } ) . subscribe ( ( e : MatSelectionListOptionEvent ) => {
281- let optionIndex : number = this . options . toArray ( ) . indexOf ( e . option ) ;
282- if ( e . option . _hasFocus ) {
283- // Check whether the option is the last item
284- if ( optionIndex < this . options . length - 1 ) {
285- this . _keyManager . setActiveItem ( optionIndex ) ;
286- } else if ( optionIndex - 1 >= 0 ) {
287- this . _keyManager . setActiveItem ( optionIndex - 1 ) ;
288- }
289- }
290- e . option . destroyed . unsubscribe ( ) ;
291- } ) ;
245+ /** Sets the focused option of the selection-list. */
246+ _setFocusedOption ( option : MatListOption ) {
247+ this . _keyManager . updateActiveItemIndex ( this . _getOptionIndex ( option ) ) ;
292248 }
293249
294- /** Map all the options' onFocus event subscriptions and merge them into one stream. */
295- private _onFocusSubscription ( ) : Subscription {
296- return RxChain . from ( this . options . changes )
297- . call ( startWith , this . options )
298- . call ( switchMap , ( options : MatListOption [ ] ) => {
299- return merge ( ...options . map ( option => option . onFocus ) ) ;
300- } ) . subscribe ( ( e : MatSelectionListOptionEvent ) => {
301- let optionIndex : number = this . options . toArray ( ) . indexOf ( e . option ) ;
302- this . _keyManager . updateActiveItemIndex ( optionIndex ) ;
303- } ) ;
250+ /** Removes an option from the selection list and updates the active item. */
251+ _removeOptionFromList ( option : MatListOption ) {
252+ if ( option . _hasFocus ) {
253+ const optionIndex = this . _getOptionIndex ( option ) ;
254+
255+ // Check whether the option is the last item
256+ if ( optionIndex > 0 ) {
257+ this . _keyManager . setPreviousItemActive ( ) ;
258+ } else if ( optionIndex === 0 && this . options . length > 1 ) {
259+ this . _keyManager . setNextItemActive ( ) ;
260+ }
261+ }
304262 }
305263
306264 /** Passes relevant key presses to our key manager. */
@@ -338,4 +296,9 @@ export class MatSelectionList extends _MatSelectionListMixinBase
338296 private _isValidIndex ( index : number ) : boolean {
339297 return index >= 0 && index < this . options . length ;
340298 }
299+
300+ /** Returns the index of the specified list option. */
301+ private _getOptionIndex ( option : MatListOption ) : number {
302+ return this . options . toArray ( ) . indexOf ( option ) ;
303+ }
341304}
0 commit comments