Skip to content

Commit 3ce5b1f

Browse files
benelliottjosephperrott
authored andcommitted
feat(autocomplete): add updatePosition() method to MatAutocompleteTrigger (#11495)
1 parent 6c3442a commit 3ce5b1f

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
@@ -1506,6 +1506,50 @@ describe('MatAutocomplete', () => {
15061506
.toEqual(Math.floor(panelBottom), `Expected panel to stay aligned after filtering.`);
15071507
}));
15081508

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

15111555
describe('Option selection', () => {
@@ -2303,6 +2347,7 @@ class AutocompleteWithNumbers {
23032347
`
23042348
})
23052349
class AutocompleteWithOnPushDelay implements OnInit {
2350+
@ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
23062351
options: string[];
23072352

23082353
ngOnInit() {

0 commit comments

Comments
 (0)