@@ -28,12 +28,17 @@ import {Subject} from 'rxjs/Subject';
2828import { map } from 'rxjs/operator/map' ;
2929import { MdSelectModule } from './index' ;
3030import { MdSelect } from './select' ;
31- import { getMdSelectDynamicMultipleError , getMdSelectNonArrayValueError } from './select-errors' ;
31+ import {
32+ getMdSelectDynamicMultipleError ,
33+ getMdSelectNonArrayValueError ,
34+ getMdSelectNonFunctionValueError
35+ } from './select-errors' ;
3236import { MdOption } from '../core/option/option' ;
3337import {
3438 FloatPlaceholderType ,
3539 MD_PLACEHOLDER_GLOBAL_OPTIONS
3640} from '../core/placeholder/placeholder-options' ;
41+ import { extendObject } from '../core/util/object-extend' ;
3742
3843
3944describe ( 'MdSelect' , ( ) => {
@@ -73,7 +78,10 @@ describe('MdSelect', () => {
7378 BasicSelectWithoutFormsPreselected ,
7479 BasicSelectWithoutFormsMultiple ,
7580 SelectInsideFormGroup ,
76- SelectWithCustomTrigger
81+ SelectWithCustomTrigger ,
82+ FalsyValueSelect ,
83+ SelectInsideFormGroup ,
84+ NgModelCompareWithSelect ,
7785 ] ,
7886 providers : [
7987 { provide : OverlayContainer , useFactory : ( ) => {
@@ -2714,8 +2722,78 @@ describe('MdSelect', () => {
27142722
27152723 } ) ;
27162724
2717- } ) ;
2725+ describe ( 'compareWith behavior' , ( ) => {
2726+ let fixture : ComponentFixture < NgModelCompareWithSelect > ;
2727+ let instance : NgModelCompareWithSelect ;
2728+
2729+ beforeEach ( async ( ( ) => {
2730+ fixture = TestBed . createComponent ( NgModelCompareWithSelect ) ;
2731+ instance = fixture . componentInstance ;
2732+ fixture . detectChanges ( ) ;
2733+ } ) ) ;
2734+
2735+ describe ( 'when comparing by value' , ( ) => {
2736+
2737+ it ( 'should have a selection' , ( ) => {
2738+ const selectedOption = instance . select . selected as MdOption ;
2739+ expect ( selectedOption . value . value ) . toEqual ( 'pizza-1' ) ;
2740+ } ) ;
2741+
2742+ it ( 'should update when making a new selection' , async ( ( ) => {
2743+ instance . options . last . _selectViaInteraction ( ) ;
2744+ fixture . detectChanges ( ) ;
2745+ fixture . whenStable ( ) . then ( ( ) => {
2746+ const selectedOption = instance . select . selected as MdOption ;
2747+ expect ( instance . selectedFood . value ) . toEqual ( 'tacos-2' ) ;
2748+ expect ( selectedOption . value . value ) . toEqual ( 'tacos-2' ) ;
2749+ } ) ;
2750+ } ) ) ;
2751+
2752+ } ) ;
2753+
2754+ describe ( 'when comparing by reference' , ( ) => {
2755+ beforeEach ( async ( ( ) => {
2756+ spyOn ( instance , 'compareByReference' ) . and . callThrough ( ) ;
2757+ instance . useCompareByReference ( ) ;
2758+ fixture . detectChanges ( ) ;
2759+ } ) ) ;
2760+
2761+ it ( 'should use the comparator' , ( ) => {
2762+ expect ( instance . compareByReference ) . toHaveBeenCalled ( ) ;
2763+ } ) ;
2764+
2765+ it ( 'should initialize with no selection despite having a value' , ( ) => {
2766+ expect ( instance . selectedFood . value ) . toBe ( 'pizza-1' ) ;
2767+ expect ( instance . select . selected ) . toBeUndefined ( ) ;
2768+ } ) ;
2769+
2770+ it ( 'should not update the selection if value is copied on change' , async ( ( ) => {
2771+ instance . options . first . _selectViaInteraction ( ) ;
2772+ fixture . detectChanges ( ) ;
2773+ fixture . whenStable ( ) . then ( ( ) => {
2774+ expect ( instance . selectedFood . value ) . toEqual ( 'steak-0' ) ;
2775+ expect ( instance . select . selected ) . toBeUndefined ( ) ;
2776+ } ) ;
2777+ } ) ) ;
2778+
2779+ } ) ;
2780+
2781+ describe ( 'when using a non-function comparator' , ( ) => {
2782+ beforeEach ( ( ) => {
2783+ instance . useNullComparator ( ) ;
2784+ } ) ;
27182785
2786+ it ( 'should throw an error' , ( ) => {
2787+ expect ( ( ) => {
2788+ fixture . detectChanges ( ) ;
2789+ } ) . toThrowError ( wrappedErrorMessage ( getMdSelectNonFunctionValueError ( ) ) ) ;
2790+ } ) ;
2791+
2792+ } ) ;
2793+
2794+ } ) ;
2795+
2796+ } ) ;
27192797
27202798@Component ( {
27212799 selector : 'basic-select' ,
@@ -3250,6 +3328,7 @@ class BasicSelectWithoutFormsMultiple {
32503328 @ViewChild ( MdSelect ) select : MdSelect ;
32513329}
32523330
3331+
32533332@Component ( {
32543333 selector : 'select-with-custom-trigger' ,
32553334 template : `
@@ -3270,3 +3349,40 @@ class SelectWithCustomTrigger {
32703349 ] ;
32713350 control = new FormControl ( ) ;
32723351}
3352+
3353+
3354+ @Component ( {
3355+ selector : 'ng-model-compare-with' ,
3356+ template : `
3357+ <md-select [ngModel]="selectedFood" (ngModelChange)="setFoodByCopy($event)"
3358+ [compareWith]="comparator">
3359+ <md-option *ngFor="let food of foods" [value]="food">{{ food.viewValue }}</md-option>
3360+ </md-select>
3361+ `
3362+ } )
3363+ class NgModelCompareWithSelect {
3364+ foods : ( { value : string , viewValue : string } ) [ ] = [
3365+ { value : 'steak-0' , viewValue : 'Steak' } ,
3366+ { value : 'pizza-1' , viewValue : 'Pizza' } ,
3367+ { value : 'tacos-2' , viewValue : 'Tacos' } ,
3368+ ] ;
3369+ selectedFood : { value : string , viewValue : string } = { value : 'pizza-1' , viewValue : 'Pizza' } ;
3370+ comparator : ( ( f1 : any , f2 : any ) => boolean ) | null = this . compareByValue ;
3371+
3372+ @ViewChild ( MdSelect ) select : MdSelect ;
3373+ @ViewChildren ( MdOption ) options : QueryList < MdOption > ;
3374+
3375+ useCompareByValue ( ) { this . comparator = this . compareByValue ; }
3376+
3377+ useCompareByReference ( ) { this . comparator = this . compareByReference ; }
3378+
3379+ useNullComparator ( ) { this . comparator = null ; }
3380+
3381+ compareByValue ( f1 : any , f2 : any ) { return f1 && f2 && f1 . value === f2 . value ; }
3382+
3383+ compareByReference ( f1 : any , f2 : any ) { return f1 === f2 ; }
3384+
3385+ setFoodByCopy ( newValue : { value : string , viewValue : string } ) {
3386+ this . selectedFood = extendObject ( { } , newValue ) ;
3387+ }
3388+ }
0 commit comments