@@ -10,7 +10,6 @@ import {FocusableOption, FocusKeyManager} from '@angular/cdk/a11y';
10
10
import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
11
11
import { SelectionModel } from '@angular/cdk/collections' ;
12
12
import { SPACE } from '@angular/cdk/keycodes' ;
13
- import { RxChain , startWith , switchMap } from '@angular/cdk/rxjs' ;
14
13
import {
15
14
AfterContentInit ,
16
15
ChangeDetectionStrategy ,
@@ -38,8 +37,6 @@ import {
38
37
mixinDisabled ,
39
38
mixinDisableRipple ,
40
39
} from '@angular/material/core' ;
41
- import { merge } from 'rxjs/observable/merge' ;
42
- import { Subscription } from 'rxjs/Subscription' ;
43
40
44
41
45
42
/** @docs -private */
@@ -55,8 +52,6 @@ export interface MatSelectionListOptionEvent {
55
52
option : MatListOption ;
56
53
}
57
54
58
- const FOCUSED_STYLE : string = 'mat-list-item-focus' ;
59
-
60
55
/**
61
56
* Component for list-options of selection-list. Each list-option can automatically
62
57
* 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';
70
65
'role' : 'option' ,
71
66
'class' : 'mat-list-item mat-list-option' ,
72
67
'(focus)' : '_handleFocus()' ,
73
- '(blur)' : '_handleBlur() ' ,
68
+ '(blur)' : '_hasFocus = false ' ,
74
69
'(click)' : '_handleClick()' ,
75
70
'tabindex' : '-1' ,
76
71
'[class.mat-list-item-disabled]' : 'disabled' ,
72
+ '[class.mat-list-item-focus]' : '_hasFocus' ,
77
73
'[attr.aria-selected]' : 'selected.toString()' ,
78
74
'[attr.aria-disabled]' : 'disabled.toString()' ,
79
75
} ,
@@ -109,18 +105,12 @@ export class MatListOption extends _MatListOptionMixinBase
109
105
get selected ( ) { return this . _selected ; }
110
106
set selected ( value : boolean ) { this . _selected = coerceBooleanProperty ( value ) ; }
111
107
112
- /** Emitted when the option is focused. */
113
- onFocus = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
114
-
115
108
/** Emitted when the option is selected. */
116
109
@Output ( ) selectChange = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
117
110
118
111
/** Emitted when the option is deselected. */
119
112
@Output ( ) deselected = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
120
113
121
- /** Emitted when the option is destroyed. */
122
- @Output ( ) destroyed = new EventEmitter < MatSelectionListOptionEvent > ( ) ;
123
-
124
114
constructor ( private _renderer : Renderer2 ,
125
115
private _element : ElementRef ,
126
116
private _changeDetector : ChangeDetectorRef ,
@@ -144,7 +134,7 @@ export class MatListOption extends _MatListOptionMixinBase
144
134
}
145
135
146
136
ngOnDestroy ( ) : void {
147
- this . destroyed . emit ( { option : this } ) ;
137
+ this . selectionList . _removeOptionFromList ( this ) ;
148
138
}
149
139
150
140
/** Toggles the selection state of the option. */
@@ -157,7 +147,6 @@ export class MatListOption extends _MatListOptionMixinBase
157
147
/** Allows for programmatic focusing of the option. */
158
148
focus ( ) : void {
159
149
this . _element . nativeElement . focus ( ) ;
160
- this . onFocus . emit ( { option : this } ) ;
161
150
}
162
151
163
152
/** Whether this list item should show a ripple effect when clicked. */
@@ -173,11 +162,7 @@ export class MatListOption extends _MatListOptionMixinBase
173
162
174
163
_handleFocus ( ) {
175
164
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 ) ;
181
166
}
182
167
183
168
/** Retrieves the DOM element of the component host. */
@@ -208,17 +193,11 @@ export class MatListOption extends _MatListOptionMixinBase
208
193
changeDetection : ChangeDetectionStrategy . OnPush
209
194
} )
210
195
export class MatSelectionList extends _MatSelectionListMixinBase
211
- implements FocusableOption , CanDisable , CanDisableRipple , AfterContentInit , OnDestroy {
196
+ implements FocusableOption , CanDisable , CanDisableRipple , AfterContentInit {
212
197
213
198
/** Tab index for the selection-list. */
214
199
_tabIndex = 0 ;
215
200
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
-
222
201
/** The FocusKeyManager which handles focus. */
223
202
_keyManager : FocusKeyManager < MatListOption > ;
224
203
@@ -238,14 +217,6 @@ export class MatSelectionList extends _MatSelectionListMixinBase
238
217
if ( this . disabled ) {
239
218
this . _tabIndex = - 1 ;
240
219
}
241
-
242
- this . _optionFocusSubscription = this . _onFocusSubscription ( ) ;
243
- this . _optionDestroyStream = this . _onDestroySubscription ( ) ;
244
- }
245
-
246
- ngOnDestroy ( ) : void {
247
- this . _optionDestroyStream . unsubscribe ( ) ;
248
- this . _optionFocusSubscription . unsubscribe ( ) ;
249
220
}
250
221
251
222
/** Focus the selection-list. */
@@ -271,36 +242,23 @@ export class MatSelectionList extends _MatSelectionListMixinBase
271
242
} ) ;
272
243
}
273
244
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 ) ) ;
292
248
}
293
249
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
+ }
304
262
}
305
263
306
264
/** Passes relevant key presses to our key manager. */
@@ -338,4 +296,9 @@ export class MatSelectionList extends _MatSelectionListMixinBase
338
296
private _isValidIndex ( index : number ) : boolean {
339
297
return index >= 0 && index < this . options . length ;
340
298
}
299
+
300
+ /** Returns the index of the specified list option. */
301
+ private _getOptionIndex ( option : MatListOption ) : number {
302
+ return this . options . toArray ( ) . indexOf ( option ) ;
303
+ }
341
304
}
0 commit comments