@@ -3508,7 +3508,7 @@ describe('MatSelect', () => {
3508
3508
expect ( trigger . textContent ) . not . toContain ( 'None' ) ;
3509
3509
} ) ) ;
3510
3510
3511
- it ( 'should not mark the reset option as selected ' , fakeAsync ( ( ) => {
3511
+ it ( 'should not mark the reset option as selected' , fakeAsync ( ( ) => {
3512
3512
options [ 5 ] . click ( ) ;
3513
3513
fixture . detectChanges ( ) ;
3514
3514
flush ( ) ;
@@ -3545,6 +3545,102 @@ describe('MatSelect', () => {
3545
3545
} ) ;
3546
3546
} ) ;
3547
3547
3548
+ describe ( 'allowing selection of nullable options' , ( ) => {
3549
+ beforeEach ( waitForAsync ( ( ) => configureMatSelectTestingModule ( [ ResetValuesSelect ] ) ) ) ;
3550
+
3551
+ let fixture : ComponentFixture < ResetValuesSelect > ;
3552
+ let trigger : HTMLElement ;
3553
+ let formField : HTMLElement ;
3554
+ let options : NodeListOf < HTMLElement > ;
3555
+ let label : HTMLLabelElement ;
3556
+
3557
+ beforeEach ( fakeAsync ( ( ) => {
3558
+ fixture = TestBed . createComponent ( ResetValuesSelect ) ;
3559
+ fixture . componentInstance . canSelectNullableOptions = true ;
3560
+ fixture . detectChanges ( ) ;
3561
+ trigger = fixture . debugElement . query ( By . css ( '.mat-mdc-select-trigger' ) ) ! . nativeElement ;
3562
+ formField = fixture . debugElement . query ( By . css ( '.mat-mdc-form-field' ) ) ! . nativeElement ;
3563
+ label = formField . querySelector ( 'label' ) ! ;
3564
+
3565
+ trigger . click ( ) ;
3566
+ fixture . detectChanges ( ) ;
3567
+ flush ( ) ;
3568
+
3569
+ options = overlayContainerElement . querySelectorAll ( 'mat-option' ) as NodeListOf < HTMLElement > ;
3570
+ options [ 0 ] . click ( ) ;
3571
+ fixture . detectChanges ( ) ;
3572
+ flush ( ) ;
3573
+ } ) ) ;
3574
+
3575
+ it ( 'should select an option with an undefined value' , fakeAsync ( ( ) => {
3576
+ options [ 4 ] . click ( ) ;
3577
+ fixture . detectChanges ( ) ;
3578
+ flush ( ) ;
3579
+
3580
+ expect ( fixture . componentInstance . control . value ) . toBe ( undefined ) ;
3581
+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3582
+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3583
+ expect ( trigger . textContent ) . toContain ( 'Undefined' ) ;
3584
+ } ) ) ;
3585
+
3586
+ it ( 'should select an option with a null value' , fakeAsync ( ( ) => {
3587
+ options [ 5 ] . click ( ) ;
3588
+ fixture . detectChanges ( ) ;
3589
+ flush ( ) ;
3590
+
3591
+ expect ( fixture . componentInstance . control . value ) . toBe ( null ) ;
3592
+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3593
+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3594
+ expect ( trigger . textContent ) . toContain ( 'Null' ) ;
3595
+ } ) ) ;
3596
+
3597
+ it ( 'should select a blank option' , fakeAsync ( ( ) => {
3598
+ options [ 6 ] . click ( ) ;
3599
+ fixture . detectChanges ( ) ;
3600
+ flush ( ) ;
3601
+
3602
+ expect ( fixture . componentInstance . control . value ) . toBe ( undefined ) ;
3603
+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3604
+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3605
+ expect ( trigger . textContent ) . toContain ( 'None' ) ;
3606
+ } ) ) ;
3607
+
3608
+ it ( 'should mark a nullable option as selected' , fakeAsync ( ( ) => {
3609
+ options [ 5 ] . click ( ) ;
3610
+ fixture . detectChanges ( ) ;
3611
+ flush ( ) ;
3612
+
3613
+ fixture . componentInstance . select . open ( ) ;
3614
+ fixture . detectChanges ( ) ;
3615
+ flush ( ) ;
3616
+
3617
+ expect ( options [ 5 ] . classList ) . toContain ( 'mdc-list-item--selected' ) ;
3618
+ } ) ) ;
3619
+
3620
+ it ( 'should not reset when any other falsy option is selected' , fakeAsync ( ( ) => {
3621
+ options [ 3 ] . click ( ) ;
3622
+ fixture . detectChanges ( ) ;
3623
+ flush ( ) ;
3624
+
3625
+ expect ( fixture . componentInstance . control . value ) . toBe ( false ) ;
3626
+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3627
+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3628
+ expect ( trigger . textContent ) . toContain ( 'Falsy' ) ;
3629
+ } ) ) ;
3630
+
3631
+ it ( 'should consider the nullable values as selected when resetting the form control' , ( ) => {
3632
+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3633
+
3634
+ fixture . componentInstance . control . reset ( ) ;
3635
+ fixture . detectChanges ( ) ;
3636
+
3637
+ expect ( fixture . componentInstance . control . value ) . toBe ( null ) ;
3638
+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3639
+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3640
+ expect ( trigger . textContent ) . toContain ( 'Null' ) ;
3641
+ } ) ;
3642
+ } ) ;
3643
+
3548
3644
describe ( 'with reset option and a form control' , ( ) => {
3549
3645
let fixture : ComponentFixture < SelectWithResetOptionAndFormControl > ;
3550
3646
let options : HTMLElement [ ] ;
@@ -5057,7 +5153,7 @@ class BasicSelectWithTheming {
5057
5153
template : `
5058
5154
<mat-form-field>
5059
5155
<mat-label>Select a food</mat-label>
5060
- <mat-select [formControl]="control">
5156
+ <mat-select [formControl]="control" [canSelectNullableOptions]="canSelectNullableOptions" >
5061
5157
@for (food of foods; track food) {
5062
5158
<mat-option [value]="food.value">{{ food.viewValue }}</mat-option>
5063
5159
}
@@ -5076,7 +5172,8 @@ class ResetValuesSelect {
5076
5172
{ viewValue : 'Undefined' } ,
5077
5173
{ value : null , viewValue : 'Null' } ,
5078
5174
] ;
5079
- control = new FormControl ( '' as string | boolean | null ) ;
5175
+ control = new FormControl ( '' as string | boolean | null | undefined ) ;
5176
+ canSelectNullableOptions = false ;
5080
5177
5081
5178
@ViewChild ( MatSelect ) select : MatSelect ;
5082
5179
}
0 commit comments