@@ -49,7 +49,8 @@ import {
49
49
ThemePalette ,
50
50
} from '@angular/material/core' ;
51
51
import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
52
- import { Subscription } from 'rxjs' ;
52
+ import { Subject } from 'rxjs' ;
53
+ import { takeUntil } from 'rxjs/operators' ;
53
54
import { MatListAvatarCssMatStyler , MatListIconCssMatStyler } from './list' ;
54
55
55
56
@@ -103,8 +104,8 @@ export class MatSelectionListChange {
103
104
// its theme. The accent theme palette is the default and doesn't need to be set.
104
105
'[class.mat-primary]' : 'color === "primary"' ,
105
106
'[class.mat-warn]' : 'color === "warn"' ,
106
- '[attr.aria-selected]' : 'selected.toString() ' ,
107
- '[attr.aria-disabled]' : 'disabled.toString() ' ,
107
+ '[attr.aria-selected]' : 'selected' ,
108
+ '[attr.aria-disabled]' : 'disabled' ,
108
109
} ,
109
110
templateUrl : 'list-option.html' ,
110
111
encapsulation : ViewEncapsulation . None ,
@@ -177,13 +178,19 @@ export class MatListOption extends _MatListOptionMixinBase
177
178
}
178
179
179
180
ngOnInit ( ) {
181
+ const list = this . selectionList ;
182
+
183
+ if ( list . _value && list . _value . some ( value => list . compareWith ( value , this . _value ) ) ) {
184
+ this . _setSelected ( true ) ;
185
+ }
186
+
187
+ const wasSelected = this . _selected ;
188
+
180
189
// List options that are selected at initialization can't be reported properly to the form
181
190
// control. This is because it takes some time until the selection-list knows about all
182
191
// available options. Also it can happen that the ControlValueAccessor has an initial value
183
192
// that should be used instead. Deferring the value change report to the next tick ensures
184
193
// that the form control value is not being overwritten.
185
- const wasSelected = this . _selected ;
186
-
187
194
Promise . resolve ( ) . then ( ( ) => {
188
195
if ( this . _selected || wasSelected ) {
189
196
this . selected = true ;
@@ -337,7 +344,7 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
337
344
* options should appear as selected. The first argument is the value of an options. The second
338
345
* one is a value from the selected value. A boolean must be returned.
339
346
*/
340
- @Input ( ) compareWith : ( o1 : any , o2 : any ) => boolean ;
347
+ @Input ( ) compareWith : ( o1 : any , o2 : any ) => boolean = ( a1 , a2 ) => a1 === a2 ;
341
348
342
349
/** Whether the selection list is disabled. */
343
350
@Input ( )
@@ -359,17 +366,17 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
359
366
/** View to model callback that should be called whenever the selected options change. */
360
367
private _onChange : ( value : any ) => void = ( _ : any ) => { } ;
361
368
362
- /** Used for storing the values that were assigned before the options were initialized . */
363
- private _tempValues : string [ ] | null ;
369
+ /** Keeps track of the currently-selected value . */
370
+ _value : string [ ] | null ;
364
371
365
- /** Subscription to sync value changes in the SelectionModel back to the SelectionList . */
366
- private _modelChanges = Subscription . EMPTY ;
372
+ /** Emits when the list has been destroyed . */
373
+ private _destroyed = new Subject < void > ( ) ;
367
374
368
375
/** View to model callback that should be called if the list or its options lost focus. */
369
376
_onTouched : ( ) => void = ( ) => { } ;
370
377
371
378
/** Whether the list has been destroyed. */
372
- private _destroyed : boolean ;
379
+ private _isDestroyed : boolean ;
373
380
374
381
constructor ( private _element : ElementRef < HTMLElement > , @Attribute ( 'tabindex' ) tabIndex : string ) {
375
382
super ( ) ;
@@ -385,13 +392,12 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
385
392
. skipPredicate ( ( ) => false )
386
393
. withAllowedModifierKeys ( [ 'shiftKey' ] ) ;
387
394
388
- if ( this . _tempValues ) {
389
- this . _setOptionsFromValues ( this . _tempValues ) ;
390
- this . _tempValues = null ;
395
+ if ( this . _value ) {
396
+ this . _setOptionsFromValues ( this . _value ) ;
391
397
}
392
398
393
399
// Sync external changes to the model back to the options.
394
- this . _modelChanges = this . selectedOptions . onChange . subscribe ( event => {
400
+ this . selectedOptions . onChange . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( event => {
395
401
if ( event . added ) {
396
402
for ( let item of event . added ) {
397
403
item . selected = true ;
@@ -417,8 +423,9 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
417
423
}
418
424
419
425
ngOnDestroy ( ) {
420
- this . _destroyed = true ;
421
- this . _modelChanges . unsubscribe ( ) ;
426
+ this . _destroyed . next ( ) ;
427
+ this . _destroyed . complete ( ) ;
428
+ this . _isDestroyed = true ;
422
429
}
423
430
424
431
/** Focuses the selection list. */
@@ -504,8 +511,10 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
504
511
// Stop reporting value changes after the list has been destroyed. This avoids
505
512
// cases where the list might wrongly reset its value once it is removed, but
506
513
// the form control is still live.
507
- if ( this . options && ! this . _destroyed ) {
508
- this . _onChange ( this . _getSelectedOptionValues ( ) ) ;
514
+ if ( this . options && ! this . _isDestroyed ) {
515
+ const value = this . _getSelectedOptionValues ( ) ;
516
+ this . _onChange ( value ) ;
517
+ this . _value = value ;
509
518
}
510
519
}
511
520
@@ -516,10 +525,10 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
516
525
517
526
/** Implemented as part of ControlValueAccessor. */
518
527
writeValue ( values : string [ ] ) : void {
528
+ this . _value = values ;
529
+
519
530
if ( this . options ) {
520
531
this . _setOptionsFromValues ( values || [ ] ) ;
521
- } else {
522
- this . _tempValues = values ;
523
532
}
524
533
}
525
534
@@ -546,11 +555,7 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
546
555
const correspondingOption = this . options . find ( option => {
547
556
// Skip options that are already in the model. This allows us to handle cases
548
557
// where the same primitive value is selected multiple times.
549
- if ( option . selected ) {
550
- return false ;
551
- }
552
-
553
- return this . compareWith ? this . compareWith ( option . value , value ) : option . value === value ;
558
+ return option . selected ? false : this . compareWith ( option . value , value ) ;
554
559
} ) ;
555
560
556
561
if ( correspondingOption ) {
0 commit comments