File tree Expand file tree Collapse file tree 4 files changed +76
-12
lines changed
material-experimental/mdc-select Expand file tree Collapse file tree 4 files changed +76
-12
lines changed Original file line number Diff line number Diff line change @@ -2134,6 +2134,30 @@ describe('MDC-based MatSelect', () => {
2134
2134
expect ( panel . scrollTop ) . toBe ( 520 , 'Expected scroll to be at the 16th option.' ) ;
2135
2135
} ) ) ;
2136
2136
2137
+ it ( 'should scroll to top when going to first option in top group' , fakeAsync ( ( ) => {
2138
+ fixture . destroy ( ) ;
2139
+ const groupFixture = TestBed . createComponent ( SelectWithGroups ) ;
2140
+ groupFixture . detectChanges ( ) ;
2141
+ groupFixture . componentInstance . select . open ( ) ;
2142
+ groupFixture . detectChanges ( ) ;
2143
+ flush ( ) ;
2144
+
2145
+ host = groupFixture . debugElement . query ( By . css ( 'mat-select' ) ) ! . nativeElement ;
2146
+ panel = overlayContainerElement . querySelector ( '.mat-mdc-select-panel' ) ! as HTMLElement ;
2147
+
2148
+ for ( let i = 0 ; i < 5 ; i ++ ) {
2149
+ dispatchKeyboardEvent ( host , 'keydown' , DOWN_ARROW ) ;
2150
+ }
2151
+
2152
+ expect ( panel . scrollTop ) . toBeGreaterThan ( 0 ) ;
2153
+
2154
+ for ( let i = 0 ; i < 5 ; i ++ ) {
2155
+ dispatchKeyboardEvent ( host , 'keydown' , UP_ARROW ) ;
2156
+ }
2157
+
2158
+ expect ( panel . scrollTop ) . toBe ( 0 ) ;
2159
+ } ) ) ;
2160
+
2137
2161
} ) ;
2138
2162
} ) ;
2139
2163
Original file line number Diff line number Diff line change @@ -23,6 +23,7 @@ import {
23
23
MatOption ,
24
24
MAT_OPTGROUP ,
25
25
MAT_OPTION_PARENT_COMPONENT ,
26
+ _countGroupLabelsBeforeOption ,
26
27
_getOptionScrollPosition ,
27
28
} from '@angular/material-experimental/mdc-core' ;
28
29
import { CdkOverlayOrigin , ConnectedPosition } from '@angular/cdk/overlay' ;
@@ -163,14 +164,22 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
163
164
164
165
if ( option ) {
165
166
const panel : HTMLElement = this . panel . nativeElement ;
167
+ const labelCount = _countGroupLabelsBeforeOption ( index , this . options , this . optionGroups ) ;
166
168
const element = option . _getHostElement ( ) ;
167
169
168
- panel . scrollTop = _getOptionScrollPosition (
169
- element . offsetTop ,
170
- element . offsetHeight ,
171
- panel . scrollTop ,
172
- panel . offsetHeight
173
- ) ;
170
+ if ( index === 0 && labelCount === 1 ) {
171
+ // If we've got one group label before the option and we're at the top option,
172
+ // scroll the list to the top. This is better UX than scrolling the list to the
173
+ // top of the option, because it allows the user to read the top group's label.
174
+ panel . scrollTop = 0 ;
175
+ } else {
176
+ panel . scrollTop = _getOptionScrollPosition (
177
+ element . offsetTop ,
178
+ element . offsetHeight ,
179
+ panel . scrollTop ,
180
+ panel . offsetHeight
181
+ ) ;
182
+ }
174
183
}
175
184
}
176
185
Original file line number Diff line number Diff line change @@ -2177,6 +2177,30 @@ describe('MatSelect', () => {
2177
2177
expect ( panel . scrollTop ) . toBe ( 512 , 'Expected scroll to be at the 16th option.' ) ;
2178
2178
} ) ) ;
2179
2179
2180
+ it ( 'should scroll to top when going to first option in top group' , fakeAsync ( ( ) => {
2181
+ fixture . destroy ( ) ;
2182
+ const groupFixture = TestBed . createComponent ( SelectWithGroups ) ;
2183
+ groupFixture . detectChanges ( ) ;
2184
+ groupFixture . componentInstance . select . open ( ) ;
2185
+ groupFixture . detectChanges ( ) ;
2186
+ flush ( ) ;
2187
+
2188
+ host = groupFixture . debugElement . query ( By . css ( 'mat-select' ) ) ! . nativeElement ;
2189
+ panel = overlayContainerElement . querySelector ( '.mat-select-panel' ) ! as HTMLElement ;
2190
+
2191
+ for ( let i = 0 ; i < 5 ; i ++ ) {
2192
+ dispatchKeyboardEvent ( host , 'keydown' , DOWN_ARROW ) ;
2193
+ }
2194
+
2195
+ expect ( panel . scrollTop ) . toBeGreaterThan ( 0 ) ;
2196
+
2197
+ for ( let i = 0 ; i < 5 ; i ++ ) {
2198
+ dispatchKeyboardEvent ( host , 'keydown' , UP_ARROW ) ;
2199
+ }
2200
+
2201
+ expect ( panel . scrollTop ) . toBe ( 0 ) ;
2202
+ } ) ) ;
2203
+
2180
2204
} ) ;
2181
2205
} ) ;
2182
2206
Original file line number Diff line number Diff line change @@ -1204,12 +1204,19 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
1204
1204
const labelCount = _countGroupLabelsBeforeOption ( index , this . options , this . optionGroups ) ;
1205
1205
const itemHeight = this . _getItemHeight ( ) ;
1206
1206
1207
- this . panel . nativeElement . scrollTop = _getOptionScrollPosition (
1208
- ( index + labelCount ) * itemHeight ,
1209
- itemHeight ,
1210
- this . panel . nativeElement . scrollTop ,
1211
- SELECT_PANEL_MAX_HEIGHT
1212
- ) ;
1207
+ if ( index === 0 && labelCount === 1 ) {
1208
+ // If we've got one group label before the option and we're at the top option,
1209
+ // scroll the list to the top. This is better UX than scrolling the list to the
1210
+ // top of the option, because it allows the user to read the top group's label.
1211
+ this . panel . nativeElement . scrollTop = 0 ;
1212
+ } else {
1213
+ this . panel . nativeElement . scrollTop = _getOptionScrollPosition (
1214
+ ( index + labelCount ) * itemHeight ,
1215
+ itemHeight ,
1216
+ this . panel . nativeElement . scrollTop ,
1217
+ SELECT_PANEL_MAX_HEIGHT
1218
+ ) ;
1219
+ }
1213
1220
}
1214
1221
1215
1222
protected _positioningSettled ( ) {
You can’t perform that action at this time.
0 commit comments