Skip to content

Commit

Permalink
feat(autocomplete): add updatePosition() method to MatAutocompleteTri…
Browse files Browse the repository at this point in the history
…gger (#11495)
  • Loading branch information
benelliott authored and josephperrott committed Aug 7, 2018
1 parent 6c3442a commit 3ce5b1f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,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 @@ -1506,6 +1506,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 @@ -2303,6 +2347,7 @@ class AutocompleteWithNumbers {
`
})
class AutocompleteWithOnPushDelay implements OnInit {
@ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
options: string[];

ngOnInit() {
Expand Down

0 comments on commit 3ce5b1f

Please sign in to comment.