@@ -745,6 +745,111 @@ describe('MdSelect', () => {
745
745
746
746
} ) ;
747
747
748
+ describe ( 'when scrolled' , ( ) => {
749
+
750
+ // Need to set the scrollTop two different ways to support
751
+ // both Chrome and Firefox.
752
+ function setScrollTop ( num : number ) {
753
+ document . body . scrollTop = num ;
754
+ document . documentElement . scrollTop = num ;
755
+ }
756
+
757
+ beforeEach ( ( ) => {
758
+ // Make the div above the select very tall, so the page will scroll
759
+ fixture . componentInstance . heightAbove = 2000 ;
760
+
761
+ // Give the select enough horizontal space to open
762
+ select . style . marginLeft = '20px' ;
763
+ select . style . marginRight = '20px' ;
764
+ } ) ;
765
+
766
+ afterEach ( ( ) => {
767
+ document . body . scrollTop = 0 ;
768
+ document . documentElement . scrollTop = 0 ;
769
+ } ) ;
770
+
771
+ it ( 'should align the first option properly when scrolled' , ( ) => {
772
+ // Give the select enough space to open
773
+ fixture . componentInstance . heightBelow = 400 ;
774
+ fixture . detectChanges ( ) ;
775
+
776
+ // Scroll the select into view
777
+ setScrollTop ( 1700 ) ;
778
+
779
+ trigger . click ( ) ;
780
+ fixture . detectChanges ( ) ;
781
+
782
+ checkTriggerAlignedWithOption ( 0 ) ;
783
+ } ) ;
784
+
785
+
786
+ it ( 'should align a centered option properly when scrolled' , ( ) => {
787
+ // Give the select enough space to open
788
+ fixture . componentInstance . heightBelow = 400 ;
789
+ fixture . detectChanges ( ) ;
790
+
791
+ fixture . componentInstance . control . setValue ( 'chips-4' ) ;
792
+ fixture . detectChanges ( ) ;
793
+
794
+ // Scroll the select into view
795
+ setScrollTop ( 1700 ) ;
796
+
797
+ trigger . click ( ) ;
798
+ fixture . detectChanges ( ) ;
799
+
800
+ checkTriggerAlignedWithOption ( 4 ) ;
801
+ } ) ;
802
+
803
+ it ( 'should fall back to "above" positioning properly when scrolled' , ( ) => {
804
+ // Give the select insufficient space to open below the trigger
805
+ fixture . componentInstance . heightBelow = 100 ;
806
+ fixture . detectChanges ( ) ;
807
+
808
+ // Scroll the select into view
809
+ setScrollTop ( 1400 ) ;
810
+
811
+ trigger . click ( ) ;
812
+ fixture . detectChanges ( ) ;
813
+
814
+ // CSS styles aren't in the tests, so position must be absolute to reflect top/left
815
+ const overlayPane = overlayContainerElement . children [ 0 ] as HTMLElement ;
816
+ overlayPane . style . position = 'absolute' ;
817
+
818
+ const triggerBottom = trigger . getBoundingClientRect ( ) . bottom ;
819
+ const overlayBottom = overlayPane . getBoundingClientRect ( ) . bottom ;
820
+
821
+ expect ( overlayBottom . toFixed ( 2 ) )
822
+ . toEqual ( triggerBottom . toFixed ( 2 ) ,
823
+ `Expected trigger bottom to align with overlay bottom.` ) ;
824
+ } ) ;
825
+
826
+ it ( 'should fall back to "below" positioning properly when scrolled' , ( ) => {
827
+ // Give plenty of space for the select to open below the trigger
828
+ fixture . componentInstance . heightBelow = 650 ;
829
+ fixture . detectChanges ( ) ;
830
+
831
+ // Select an option too low in the list to fit in limited space above
832
+ fixture . componentInstance . control . setValue ( 'sushi-7' ) ;
833
+ fixture . detectChanges ( ) ;
834
+
835
+ // Scroll the select so that it has insufficient space to open above the trigger
836
+ setScrollTop ( 1950 ) ;
837
+
838
+ trigger . click ( ) ;
839
+ fixture . detectChanges ( ) ;
840
+
841
+ // CSS styles aren't in the tests, so position must be absolute to reflect top/left
842
+ const overlayPane = overlayContainerElement . children [ 0 ] as HTMLElement ;
843
+ overlayPane . style . position = 'absolute' ;
844
+
845
+ const triggerTop = trigger . getBoundingClientRect ( ) . top ;
846
+ const overlayTop = overlayPane . getBoundingClientRect ( ) . top ;
847
+
848
+ expect ( overlayTop . toFixed ( 2 ) )
849
+ . toEqual ( triggerTop . toFixed ( 2 ) , `Expected trigger top to align with overlay top.` ) ;
850
+ } ) ;
851
+ } ) ;
852
+
748
853
describe ( 'x-axis positioning' , ( ) => {
749
854
750
855
beforeEach ( ( ) => {
@@ -1037,11 +1142,13 @@ describe('MdSelect', () => {
1037
1142
@Component ( {
1038
1143
selector : 'basic-select' ,
1039
1144
template : `
1145
+ <div [style.height.px]="heightAbove"></div>
1040
1146
<md-select placeholder="Food" [formControl]="control" [required]="isRequired">
1041
1147
<md-option *ngFor="let food of foods" [value]="food.value" [disabled]="food.disabled">
1042
1148
{{ food.viewValue }}
1043
1149
</md-option>
1044
1150
</md-select>
1151
+ <div [style.height.px]="heightBelow"></div>
1045
1152
`
1046
1153
} )
1047
1154
class BasicSelect {
@@ -1057,6 +1164,8 @@ class BasicSelect {
1057
1164
] ;
1058
1165
control = new FormControl ( ) ;
1059
1166
isRequired : boolean ;
1167
+ heightAbove = 0 ;
1168
+ heightBelow = 0 ;
1060
1169
1061
1170
@ViewChild ( MdSelect ) select : MdSelect ;
1062
1171
@ViewChildren ( MdOption ) options : QueryList < MdOption > ;
0 commit comments