Skip to content

Commit 0070cde

Browse files
benelliottjosephperrott
authored andcommitted
feat(autocomplete): add updatePosition() method to MatAutocompleteTrigger (#11495)
1 parent b4f08bb commit 0070cde

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,16 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
230230
}
231231
}
232232

233+
/**
234+
* Updates the position of the autocomplete suggestion panel to ensure that it fits all options
235+
* within the viewport.
236+
*/
237+
updatePosition(): void {
238+
if (this._overlayAttached) {
239+
this._overlayRef!.updatePosition();
240+
}
241+
}
242+
233243
/**
234244
* A stream of actions that should close the autocomplete panel, including
235245
* when an option is selected, on blur, and when TAB is pressed.

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,50 @@ describe('MatAutocomplete', () => {
14971497
.toEqual(Math.floor(panelBottom), `Expected panel to stay aligned after filtering.`);
14981498
}));
14991499

1500+
it('should fall back to above position when requested if options are added while ' +
1501+
'the panel is open', fakeAsync(() => {
1502+
let fixture = createComponent(AutocompleteWithOnPushDelay);
1503+
fixture.detectChanges();
1504+
1505+
let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
1506+
let inputReference = fixture.debugElement.query(By.css('.mat-form-field-flex')).nativeElement;
1507+
1508+
// Push the element down so it has a little bit of space, but not enough to render.
1509+
inputReference.style.bottom = '10px';
1510+
inputReference.style.position = 'fixed';
1511+
1512+
// Focus the input to load the deferred options.
1513+
dispatchFakeEvent(inputEl, 'focusin');
1514+
tick(1000);
1515+
1516+
fixture.detectChanges();
1517+
tick();
1518+
1519+
const inputBottom = inputReference.getBoundingClientRect().bottom;
1520+
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel')!;
1521+
const panelTop = panel.getBoundingClientRect().top;
1522+
1523+
expect(Math.floor(inputBottom))
1524+
.toEqual(Math.floor(panelTop),
1525+
`Expected panel top to be below input before repositioning.`);
1526+
1527+
// Request a position update now that there are too many suggestions to fit in the viewport.
1528+
fixture.componentInstance.trigger.updatePosition();
1529+
1530+
const inputTop = inputReference.getBoundingClientRect().top;
1531+
const panelBottom = panel.getBoundingClientRect().bottom;
1532+
1533+
expect(Math.floor(inputTop))
1534+
.toEqual(Math.floor(panelBottom),
1535+
`Expected panel to fall back to above position after repositioning.`);
1536+
}));
1537+
1538+
it('should not throw if a panel reposition is requested while the panel is closed', () => {
1539+
let fixture = createComponent(SimpleAutocomplete);
1540+
fixture.detectChanges();
1541+
1542+
expect(() => fixture.componentInstance.trigger.updatePosition()).not.toThrow();
1543+
});
15001544
});
15011545

15021546
describe('Option selection', () => {
@@ -2294,6 +2338,7 @@ class AutocompleteWithNumbers {
22942338
`
22952339
})
22962340
class AutocompleteWithOnPushDelay implements OnInit {
2341+
@ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
22972342
options: string[];
22982343

22992344
ngOnInit() {

0 commit comments

Comments
 (0)