Skip to content

Commit 6b9a3c3

Browse files
committed
fix(overlay): make config immutable for existing refs
This changes makes the OverlayConfig instance in OverlatRef immutable. Calling `getConfig` will now return a clone of the config to make clear that it cannot be modified directly to change the state of the overlay. This also updates the `updateSize` method to accept a partial config to apply to the existing config (and make a new config instance). This *also* tightens up the typings on Portal.attach BREAKING CHANGE: OverlayRef.getConfig returns an immutable version of the config object. BREAKING CHANGE: OverlayRef.updateSize now accepts a OverlaySizeConfig rather than being based on the existing config object.
1 parent 0d9f786 commit 6b9a3c3

File tree

5 files changed

+65
-33
lines changed

5 files changed

+65
-33
lines changed

src/cdk/overlay/overlay-directives.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges {
337337
}
338338

339339
this._position.withDirection(this.dir);
340-
this._overlayRef.getConfig().direction = this.dir;
340+
this._overlayRef.setDirection(this.dir);
341341
this._initEscapeListener();
342342

343343
if (!this._overlayRef.hasAttached()) {

src/cdk/overlay/overlay-ref.ts

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {NgZone} from '@angular/core';
10-
import {PortalHost, Portal} from '@angular/cdk/portal';
11-
import {OverlayConfig} from './overlay-config';
9+
import {Direction} from '@angular/cdk/bidi';
10+
import {ComponentPortal, Portal, PortalHost, TemplatePortal} from '@angular/cdk/portal';
11+
import {ComponentRef, EmbeddedViewRef, NgZone} from '@angular/core';
1212
import {Observable} from 'rxjs/Observable';
1313
import {Subject} from 'rxjs/Subject';
14+
import {OverlayConfig} from './overlay-config';
15+
1416

17+
/** An object where all of its properties cannot be written. */
18+
export type ImmutableObject<T> = {
19+
readonly [P in keyof T]: T[P];
20+
};
1521

1622
/**
1723
* Reference to an overlay that has been created with the Overlay service.
@@ -26,7 +32,7 @@ export class OverlayRef implements PortalHost {
2632
constructor(
2733
private _portalHost: PortalHost,
2834
private _pane: HTMLElement,
29-
private _config: OverlayConfig,
35+
private _config: ImmutableObject<OverlayConfig>,
3036
private _ngZone: NgZone) {
3137

3238
if (_config.scrollStrategy) {
@@ -39,8 +45,14 @@ export class OverlayRef implements PortalHost {
3945
return this._pane;
4046
}
4147

48+
attach<T>(portal: ComponentPortal<T>): ComponentRef<T>;
49+
attach<T>(portal: TemplatePortal<T>): EmbeddedViewRef<T>;
50+
attach(portal: any): any;
51+
4252
/**
43-
* Attaches the overlay to a portal instance and adds the backdrop.
53+
* Attaches content, given via a Portal, to the overlay.
54+
* If the overlay is configured to have a backdrop, it will be created.
55+
*
4456
* @param portal Portal instance to which to attach the overlay.
4557
* @returns The portal attachment result.
4658
*/
@@ -53,8 +65,8 @@ export class OverlayRef implements PortalHost {
5365

5466
// Update the pane element with the given configuration.
5567
this._updateStackingOrder();
56-
this.updateSize();
57-
this.updateDirection();
68+
this._updateElementSize();
69+
this._updateElementDirection();
5870
this.updatePosition();
5971

6072
if (this._config.scrollStrategy) {
@@ -107,9 +119,7 @@ export class OverlayRef implements PortalHost {
107119
return detachmentResult;
108120
}
109121

110-
/**
111-
* Cleans up the overlay from the DOM.
112-
*/
122+
/** Cleans up the overlay from the DOM. */
113123
dispose(): void {
114124
if (this._config.positionStrategy) {
115125
this._config.positionStrategy.dispose();
@@ -127,34 +137,28 @@ export class OverlayRef implements PortalHost {
127137
this._detachments.complete();
128138
}
129139

130-
/**
131-
* Checks whether the overlay has been attached.
132-
*/
140+
/** Whether the overlay has attached content. */
133141
hasAttached(): boolean {
134142
return this._portalHost.hasAttached();
135143
}
136144

137-
/**
138-
* Returns an observable that emits when the backdrop has been clicked.
139-
*/
145+
/** Gets an observable that emits when the backdrop has been clicked. */
140146
backdropClick(): Observable<void> {
141147
return this._backdropClick.asObservable();
142148
}
143149

144-
/** Returns an observable that emits when the overlay has been attached. */
150+
/** Gets an observable that emits when the overlay has been attached. */
145151
attachments(): Observable<void> {
146152
return this._attachments.asObservable();
147153
}
148154

149-
/** Returns an observable that emits when the overlay has been detached. */
155+
/** Gets an observable that emits when the overlay has been detached. */
150156
detachments(): Observable<void> {
151157
return this._detachments.asObservable();
152158
}
153159

154-
/**
155-
* Gets the current config of the overlay.
156-
*/
157-
getConfig(): OverlayConfig {
160+
/** Gets the the current overlay configuration, which is immutable. */
161+
getConfig(): ImmutableObject<OverlayConfig> {
158162
return this._config;
159163
}
160164

@@ -165,13 +169,25 @@ export class OverlayRef implements PortalHost {
165169
}
166170
}
167171

172+
/** Update the size properties of the overlay. */
173+
updateSize(sizeConfig: OverlaySizeConfig) {
174+
this._config = {...this._config, ...sizeConfig};
175+
this._updateElementSize();
176+
}
177+
178+
/** Sets the LTR/RTL direction for the overlay. */
179+
setDirection(dir: Direction) {
180+
this._config = {...this._config, direction: dir};
181+
this._updateElementDirection();
182+
}
183+
168184
/** Updates the text direction of the overlay panel. */
169-
private updateDirection() {
185+
private _updateElementDirection() {
170186
this._pane.setAttribute('dir', this._config.direction!);
171187
}
172188

173-
/** Updates the size of the overlay based on the overlay config. */
174-
updateSize() {
189+
/** Updates the size of the overlay element based on the overlay config. */
190+
private _updateElementSize() {
175191
if (this._config.width || this._config.width === 0) {
176192
this._pane.style.width = formatCssUnit(this._config.width);
177193
}
@@ -220,10 +236,12 @@ export class OverlayRef implements PortalHost {
220236
this._backdropElement.addEventListener('click', () => this._backdropClick.next(null));
221237

222238
// Add class to fade-in the backdrop after one frame.
223-
requestAnimationFrame(() => {
224-
if (this._backdropElement) {
225-
this._backdropElement.classList.add('cdk-overlay-backdrop-showing');
226-
}
239+
this._ngZone.runOutsideAngular(() => {
240+
requestAnimationFrame(() => {
241+
if (this._backdropElement) {
242+
this._backdropElement.classList.add('cdk-overlay-backdrop-showing');
243+
}
244+
});
227245
});
228246
}
229247

@@ -284,3 +302,14 @@ export class OverlayRef implements PortalHost {
284302
function formatCssUnit(value: number | string) {
285303
return typeof value === 'string' ? value as string : `${value}px`;
286304
}
305+
306+
307+
/** Size properties for an overlay. */
308+
export interface OverlaySizeConfig {
309+
width?: number | string;
310+
height?: number | string;
311+
minWidth?: number | string;
312+
minHeight?: number | string;
313+
maxWidth?: number | string;
314+
maxHeight?: number | string;
315+
}

src/cdk/portal/portal.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ export abstract class BasePortalHost implements PortalHost {
179179
return !!this._attachedPortal;
180180
}
181181

182+
attach<T>(portal: ComponentPortal<T>): ComponentRef<T>;
183+
attach<T>(portal: TemplatePortal<T>): EmbeddedViewRef<T>;
184+
attach(portal: any): any;
185+
182186
attach(portal: Portal<any>): any {
183187
if (!portal) {
184188
throwNullPortalError();

src/cdk/scrolling/scrolling.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
### Scrolling
22

3-
Some things to help with scrollling.
3+
Some things to help with scrollling.

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
451451
this._overlayRef = this._overlay.create(this._getOverlayConfig());
452452
} else {
453453
/** Update the panel width, in case the host width has changed */
454-
this._overlayRef.getConfig().width = this._getHostWidth();
455-
this._overlayRef.updateSize();
454+
this._overlayRef.updateSize({width: this._getHostWidth()});
456455
}
457456

458457
if (this._overlayRef && !this._overlayRef.hasAttached()) {

0 commit comments

Comments
 (0)