Skip to content

Commit cdad90b

Browse files
authored
feat(overlay): make overlays synchronous (#1079)
1 parent abcc6af commit cdad90b

File tree

16 files changed

+167
-311
lines changed

16 files changed

+167
-311
lines changed

src/demo-app/dialog/dialog-demo.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@ export class DialogDemo {
2121
let config = new MdDialogConfig();
2222
config.viewContainerRef = this.viewContainerRef;
2323

24-
this.dialog.open(JazzDialog, config).then(ref => {
25-
this.dialogRef = ref;
24+
this.dialogRef = this.dialog.open(JazzDialog, config);
2625

27-
this.dialogRef.afterClosed().subscribe(result => {
28-
this.lastCloseResult = result;
29-
this.dialogRef = null;
30-
});
26+
this.dialogRef.afterClosed().subscribe(result => {
27+
this.lastCloseResult = result;
28+
this.dialogRef = null;
3129
});
3230
}
3331
}

src/demo-app/overlay/overlay-demo.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ export class OverlayDemo {
4444

4545
this.nextPosition += 30;
4646

47-
this.overlay.create(config).then(ref => {
48-
ref.attach(new ComponentPortal(RotiniPanel, this.viewContainerRef));
49-
});
47+
let overlayRef = this.overlay.create(config);
48+
overlayRef.attach(new ComponentPortal(RotiniPanel, this.viewContainerRef));
5049
}
5150

5251
openFusilliPanel() {
@@ -59,9 +58,8 @@ export class OverlayDemo {
5958

6059
this.nextPosition += 30;
6160

62-
this.overlay.create(config).then(ref => {
63-
ref.attach(this.templatePortals.first);
64-
});
61+
let overlayRef = this.overlay.create(config);
62+
overlayRef.attach(this.templatePortals.first);
6563
}
6664

6765
openSpaghettiPanel() {
@@ -75,9 +73,8 @@ export class OverlayDemo {
7573
let config = new OverlayState();
7674
config.positionStrategy = strategy;
7775

78-
this.overlay.create(config).then(ref => {
79-
ref.attach(new ComponentPortal(SpagettiPanel, this.viewContainerRef));
80-
});
76+
let overlayRef = this.overlay.create(config);
77+
overlayRef.attach(new ComponentPortal(SpagettiPanel, this.viewContainerRef));
8178
}
8279
}
8380

src/lib/core/overlay/overlay-directives.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,8 @@ export class ConnectedOverlayDirective implements OnInit, OnDestroy {
9393
{originX: this.positions[0].overlayX, originY: this.positions[0].originY},
9494
{overlayX: this.positions[0].overlayX, overlayY: this.positions[0].overlayY});
9595

96-
this._overlay.create(overlayConfig).then(ref => {
97-
this._overlayRef = ref;
98-
this._overlayRef.attach(this._templatePortal);
99-
});
96+
this._overlayRef = this._overlay.create(overlayConfig);
97+
this._overlayRef.attach(this._templatePortal);
10098
}
10199

102100
/** Destroys the overlay created by this directive. */

src/lib/core/overlay/overlay-ref.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,11 @@ export class OverlayRef implements PortalHost {
1111
private _pane: HTMLElement,
1212
private _state: OverlayState) { }
1313

14-
attach(portal: Portal<any>): Promise<any> {
15-
let attachPromise = this._portalHost.attach(portal);
14+
attach(portal: Portal<any>): any {
15+
let attachResult = this._portalHost.attach(portal);
16+
this.updatePosition();
1617

17-
// Don't chain the .then() call in the return because we want the result of portalHost.attach
18-
// to be returned from this method.
19-
attachPromise.then(() => {
20-
this.updatePosition();
21-
});
22-
23-
return attachPromise;
18+
return attachResult;
2419
}
2520

2621
detach(): Promise<any> {

src/lib/core/overlay/overlay.spec.ts

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import {inject, fakeAsync, flushMicrotasks, TestBed, async} from '@angular/core/testing';
1+
import {inject, TestBed, async} from '@angular/core/testing';
22
import {NgModule, Component, ViewChild, ViewContainerRef} from '@angular/core';
33
import {TemplatePortalDirective, PortalModule} from '../portal/portal-directives';
44
import {TemplatePortal, ComponentPortal} from '../portal/portal';
55
import {Overlay} from './overlay';
66
import {OverlayContainer} from './overlay-container';
7-
import {OverlayRef} from './overlay-ref';
87
import {OverlayState} from './overlay-state';
98
import {PositionStrategy} from './position/position-strategy';
109
import {OverlayModule} from './overlay-directives';
@@ -30,68 +29,43 @@ describe('Overlay', () => {
3029
TestBed.compileComponents();
3130
}));
3231

33-
beforeEach(fakeAsync(inject([Overlay], (o: Overlay) => {
32+
beforeEach(inject([Overlay], (o: Overlay) => {
3433
overlay = o;
3534

3635
let fixture = TestBed.createComponent(TestComponentWithTemplatePortals);
3736
fixture.detectChanges();
3837
templatePortal = fixture.componentInstance.templatePortal;
3938
componentPortal = new ComponentPortal(PizzaMsg, fixture.componentInstance.viewContainerRef);
39+
}));
4040

41-
flushMicrotasks();
42-
})));
43-
44-
it('should load a component into an overlay', fakeAsync(() => {
45-
let overlayRef: OverlayRef;
46-
47-
overlay.create().then(ref => {
48-
overlayRef = ref;
49-
overlayRef.attach(componentPortal);
50-
});
51-
52-
flushMicrotasks();
41+
it('should load a component into an overlay', () => {
42+
let overlayRef = overlay.create();
43+
overlayRef.attach(componentPortal);
5344

5445
expect(overlayContainerElement.textContent).toContain('Pizza');
5546

5647
overlayRef.dispose();
5748
expect(overlayContainerElement.childNodes.length).toBe(0);
5849
expect(overlayContainerElement.textContent).toBe('');
59-
}));
60-
61-
it('should load a template portal into an overlay', fakeAsync(() => {
62-
let overlayRef: OverlayRef;
63-
64-
overlay.create().then(ref => {
65-
overlayRef = ref;
66-
overlayRef.attach(templatePortal);
67-
});
50+
});
6851

69-
flushMicrotasks();
52+
it('should load a template portal into an overlay', () => {
53+
let overlayRef = overlay.create();
54+
overlayRef.attach(templatePortal);
7055

7156
expect(overlayContainerElement.textContent).toContain('Cake');
7257

7358
overlayRef.dispose();
7459
expect(overlayContainerElement.childNodes.length).toBe(0);
7560
expect(overlayContainerElement.textContent).toBe('');
76-
}));
77-
78-
it('should open multiple overlays', fakeAsync(() => {
79-
let pizzaOverlayRef: OverlayRef;
80-
let cakeOverlayRef: OverlayRef;
81-
82-
overlay.create().then(ref => {
83-
pizzaOverlayRef = ref;
84-
pizzaOverlayRef.attach(componentPortal);
85-
});
86-
87-
flushMicrotasks();
61+
});
8862

89-
overlay.create().then(ref => {
90-
cakeOverlayRef = ref;
91-
cakeOverlayRef.attach(templatePortal);
92-
});
63+
it('should open multiple overlays', () => {
64+
let pizzaOverlayRef = overlay.create();
65+
pizzaOverlayRef.attach(componentPortal);
9366

94-
flushMicrotasks();
67+
let cakeOverlayRef = overlay.create();
68+
cakeOverlayRef.attach(templatePortal);
9569

9670
expect(overlayContainerElement.childNodes.length).toBe(2);
9771
expect(overlayContainerElement.textContent).toContain('Pizza');
@@ -104,7 +78,7 @@ describe('Overlay', () => {
10478
cakeOverlayRef.dispose();
10579
expect(overlayContainerElement.childNodes.length).toBe(0);
10680
expect(overlayContainerElement.textContent).toBe('');
107-
}));
81+
});
10882

10983
describe('applyState', () => {
11084
let state: OverlayState;
@@ -113,17 +87,13 @@ describe('Overlay', () => {
11387
state = new OverlayState();
11488
});
11589

116-
it('should apply the positioning strategy', fakeAsync(() => {
90+
it('should apply the positioning strategy', () => {
11791
state.positionStrategy = new FakePositionStrategy();
11892

119-
overlay.create(state).then(ref => {
120-
ref.attach(componentPortal);
121-
});
122-
123-
flushMicrotasks();
93+
overlay.create(state).attach(componentPortal);
12494

12595
expect(overlayContainerElement.querySelectorAll('.fake-positioned').length).toBe(1);
126-
}));
96+
});
12797
});
12898
});
12999

src/lib/core/overlay/overlay.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export class Overlay {
3636
* @param state State to apply to the overlay.
3737
* @returns A reference to the created overlay.
3838
*/
39-
create(state: OverlayState = defaultState): Promise<OverlayRef> {
40-
return this._createPaneElement().then(pane => this._createOverlayRef(pane, state));
39+
create(state: OverlayState = defaultState): OverlayRef {
40+
return this._createOverlayRef(this._createPaneElement(), state);
4141
}
4242

4343
/**
@@ -52,14 +52,14 @@ export class Overlay {
5252
* Creates the DOM element for an overlay and appends it to the overlay container.
5353
* @returns Promise resolving to the created element.
5454
*/
55-
private _createPaneElement(): Promise<HTMLElement> {
55+
private _createPaneElement(): HTMLElement {
5656
var pane = document.createElement('div');
5757
pane.id = `md-overlay-${nextUniqueId++}`;
5858
pane.classList.add('md-overlay-pane');
5959

6060
this._overlayContainer.getContainerElement().appendChild(pane);
6161

62-
return Promise.resolve(pane);
62+
return pane;
6363
}
6464

6565
/**

src/lib/core/portal/dom-portal-host.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class DomPortalHost extends BasePortalHost {
1717
}
1818

1919
/** Attach the given ComponentPortal to DOM element using the ComponentFactoryResolver. */
20-
attachComponentPortal<T>(portal: ComponentPortal<T>): Promise<ComponentRef<T>> {
20+
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
2121
if (portal.viewContainerRef == null) {
2222
throw new MdComponentPortalAttachedToDomWithoutOriginError();
2323
}
@@ -32,10 +32,10 @@ export class DomPortalHost extends BasePortalHost {
3232
this._hostDomElement.appendChild(hostView.rootNodes[0]);
3333
this.setDisposeFn(() => ref.destroy());
3434

35-
return Promise.resolve(ref);
35+
return ref;
3636
}
3737

38-
attachTemplatePortal(portal: TemplatePortal): Promise<Map<string, any>> {
38+
attachTemplatePortal(portal: TemplatePortal): Map<string, any> {
3939
let viewContainer = portal.viewContainerRef;
4040
let viewRef = viewContainer.createEmbeddedView(portal.templateRef);
4141

@@ -49,7 +49,7 @@ export class DomPortalHost extends BasePortalHost {
4949
}));
5050

5151
// TODO(jelbourn): Return locals from view.
52-
return Promise.resolve(new Map<string, any>());
52+
return new Map<string, any>();
5353
}
5454

5555
dispose(): void {

src/lib/core/portal/portal-directives.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class PortalHostDirective extends BasePortalHost {
5959
}
6060

6161
/** Attach the given ComponentPortal to this PortlHost using the ComponentFactoryResolver. */
62-
attachComponentPortal<T>(portal: ComponentPortal<T>): Promise<ComponentRef<T>> {
62+
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
6363
portal.setAttachedHost(this);
6464

6565
// If the portal specifies an origin, use that as the logical location of the component
@@ -75,30 +75,30 @@ export class PortalHostDirective extends BasePortalHost {
7575
portal.injector || viewContainerRef.parentInjector);
7676

7777
this.setDisposeFn(() => ref.destroy());
78-
return Promise.resolve(ref);
78+
return ref;
7979
}
8080

8181
/** Attach the given TemplatePortal to this PortlHost as an embedded View. */
82-
attachTemplatePortal(portal: TemplatePortal): Promise<Map<string, any>> {
82+
attachTemplatePortal(portal: TemplatePortal): Map<string, any> {
8383
portal.setAttachedHost(this);
8484

8585
this._viewContainerRef.createEmbeddedView(portal.templateRef);
8686
this.setDisposeFn(() => this._viewContainerRef.clear());
8787

8888
// TODO(jelbourn): return locals from view
89-
return Promise.resolve(new Map<string, any>());
89+
return new Map<string, any>();
9090
}
9191

9292
/** Detatches the currently attached Portal (if there is one) and attaches the given Portal. */
9393
private _replaceAttachedPortal(p: Portal<any>): void {
94-
let maybeDetach = this.hasAttached() ? this.detach() : Promise.resolve(null);
95-
96-
maybeDetach.then(() => {
97-
if (p) {
98-
this.attach(p);
99-
this._portal = p;
100-
}
101-
});
94+
if (this.hasAttached()) {
95+
this.detach();
96+
}
97+
98+
if (p) {
99+
this.attach(p);
100+
this._portal = p;
101+
}
102102
}
103103
}
104104

src/lib/core/portal/portal.spec.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,7 @@ describe('Portals', () => {
186186
it('should attach and detach a component portal', fakeAsync(() => {
187187
let portal = new ComponentPortal(PizzaMsg, someViewContainerRef);
188188

189-
let componentInstance: PizzaMsg;
190-
portal.attach(host).then(ref => {
191-
componentInstance = ref.instance;
192-
});
189+
let componentInstance: PizzaMsg = portal.attach(host).instance;
193190

194191
flushMicrotasks();
195192

@@ -210,10 +207,7 @@ describe('Portals', () => {
210207
let chocolateInjector = new ChocolateInjector(someInjector);
211208
let portal = new ComponentPortal(PizzaMsg, someViewContainerRef, chocolateInjector);
212209

213-
let componentInstance: PizzaMsg;
214-
portal.attach(host).then(ref => {
215-
componentInstance = ref.instance;
216-
});
210+
let componentInstance: PizzaMsg = portal.attach(host).instance;
217211

218212
flushMicrotasks();
219213
fixture.detectChanges();

0 commit comments

Comments
 (0)