Skip to content

Commit

Permalink
fix(connected-overlay): better handling of dynamic content (#4250)
Browse files Browse the repository at this point in the history
* fix(connected-overlay): better handling of dynamic content

* Refactors the `ConnectedPositionStrategy` to be able to use `right` and `bottom` to position the panel. This will allow the element to keep its position automatically, even if the element's size changes.
* Removes the uses of the `FakeViewportRuler` in some of the unit tests since it doesn't work very well when the element is positioned relatively to the right edge of the screen.
* Rounds down the values when testing positioning. This is necessary, because some browsers (particularly Chrome on Windows) can have some subpixel deviations.

Fixes #4155.

* refactor: move new logic into _setElementPosition method
  • Loading branch information
crisbeto authored and andrewseguin committed May 4, 2017
1 parent f8a2860 commit 525ce1e
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 233 deletions.
21 changes: 8 additions & 13 deletions src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {Subscription} from 'rxjs/Subscription';
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW, HOME, END} from '../core/keyboard/keycodes';
import {MdOption} from '../core/option/option';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
import {FakeViewportRuler} from '../core/overlay/position/fake-viewport-ruler';
import {MdAutocomplete} from './autocomplete';
import {MdInputContainer} from '../input/input-container';
import {Observable} from 'rxjs/Observable';
Expand Down Expand Up @@ -65,10 +63,7 @@ describe('MdAutocomplete', () => {

return {getContainerElement: () => overlayContainerElement};
}},
{provide: Dir, useFactory: () => {
return {value: dir};
}},
{provide: ViewportRuler, useClass: FakeViewportRuler},
{provide: Dir, useFactory: () => ({value: dir})},
{provide: ScrollDispatcher, useFactory: () => {
return {scrolled: (delay: number, callback: () => any) => {
return scrolledSubject.asObservable().subscribe(callback);
Expand Down Expand Up @@ -933,8 +928,8 @@ describe('MdAutocomplete', () => {
const panelTop = panel.getBoundingClientRect().top;

// Panel is offset by 6px in styles so that the underline has room to display.
expect((inputBottom + 6).toFixed(1))
.toEqual(panelTop.toFixed(1), `Expected panel top to match input bottom by default.`);
expect(Math.floor(inputBottom + 6))
.toEqual(Math.floor(panelTop), `Expected panel top to match input bottom by default.`);
expect(fixture.componentInstance.trigger.autocomplete.positionY)
.toEqual('below', `Expected autocomplete positionY to default to below.`);
});
Expand All @@ -956,7 +951,7 @@ describe('MdAutocomplete', () => {
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel');
const panelTop = panel.getBoundingClientRect().top;

expect((inputBottom + 6).toFixed(1)).toEqual(panelTop.toFixed(1),
expect(Math.floor(inputBottom + 6)).toEqual(Math.floor(panelTop),
'Expected panel top to match input bottom after scrolling.');

document.body.removeChild(spacer);
Expand All @@ -975,8 +970,8 @@ describe('MdAutocomplete', () => {
const panelBottom = panel.getBoundingClientRect().bottom;

// Panel is offset by 24px in styles so that the label has room to display.
expect((inputTop - 24).toFixed(1))
.toEqual(panelBottom.toFixed(1), `Expected panel to fall back to above position.`);
expect(Math.floor(inputTop - 24))
.toEqual(Math.floor(panelBottom), `Expected panel to fall back to above position.`);
expect(fixture.componentInstance.trigger.autocomplete.positionY)
.toEqual('above', `Expected autocomplete positionY to be "above" if panel won't fit.`);
});
Expand All @@ -998,8 +993,8 @@ describe('MdAutocomplete', () => {
const panelBottom = panel.getBoundingClientRect().bottom;

// Panel is offset by 24px in styles so that the label has room to display.
expect((inputTop - 24).toFixed(1))
.toEqual(panelBottom.toFixed(1), `Expected panel to stay aligned after filtering.`);
expect(Math.floor(inputTop - 24))
.toEqual(Math.floor(panelBottom), `Expected panel to stay aligned after filtering.`);
expect(fixture.componentInstance.trigger.autocomplete.positionY)
.toEqual('above', `Expected autocomplete positionY to be "above" if panel won't fit.`);
});
Expand Down
6 changes: 4 additions & 2 deletions src/lib/core/overlay/_overlay.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
// The container should be the size of the viewport.
top: 0;
left: 0;
height: 100%;
width: 100%;

// Note: we prefer viewport units, because they aren't being offset by the global scrollbar.
height: 100vh;
width: 100vw;
}

// The overlay-container is an invisible element which contains all individual overlays.
Expand Down
Loading

0 comments on commit 525ce1e

Please sign in to comment.