Skip to content

feat(autocomplete): add updatePosition() method to MatAutocompleteTrigger #11495

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,16 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
}
}

/**
* Updates the position of the autocomplete suggestion panel to ensure that it fits all options
* within the viewport.
*/
updatePosition(): void {
if (this._overlayAttached) {
this._overlayRef!.updatePosition();
}
}

/**
* A stream of actions that should close the autocomplete panel, including
* when an option is selected, on blur, and when TAB is pressed.
Expand Down
45 changes: 45 additions & 0 deletions src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,50 @@ describe('MatAutocomplete', () => {
.toEqual(Math.floor(panelBottom), `Expected panel to stay aligned after filtering.`);
}));

it('should fall back to above position when requested if options are added while ' +
'the panel is open', fakeAsync(() => {
let fixture = createComponent(AutocompleteWithOnPushDelay);
fixture.detectChanges();

let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
let inputReference = fixture.debugElement.query(By.css('.mat-form-field-flex')).nativeElement;

// Push the element down so it has a little bit of space, but not enough to render.
inputReference.style.bottom = '10px';
inputReference.style.position = 'fixed';

// Focus the input to load the deferred options.
dispatchFakeEvent(inputEl, 'focusin');
tick(1000);

fixture.detectChanges();
tick();

const inputBottom = inputReference.getBoundingClientRect().bottom;
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel')!;
const panelTop = panel.getBoundingClientRect().top;

expect(Math.floor(inputBottom))
.toEqual(Math.floor(panelTop),
`Expected panel top to be below input before repositioning.`);

// Request a position update now that there are too many suggestions to fit in the viewport.
fixture.componentInstance.trigger.updatePosition();

const inputTop = inputReference.getBoundingClientRect().top;
const panelBottom = panel.getBoundingClientRect().bottom;

expect(Math.floor(inputTop))
.toEqual(Math.floor(panelBottom),
`Expected panel to fall back to above position after repositioning.`);
}));

it('should not throw if a panel reposition is requested while the panel is closed', () => {
let fixture = createComponent(SimpleAutocomplete);
fixture.detectChanges();

expect(() => fixture.componentInstance.trigger.updatePosition()).not.toThrow();
});
});

describe('Option selection', () => {
Expand Down Expand Up @@ -2198,6 +2242,7 @@ class AutocompleteWithNumbers {
`
})
class AutocompleteWithOnPushDelay implements OnInit {
@ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
options: string[];

ngOnInit() {
Expand Down