Skip to content

Commit 8e6720b

Browse files
crisbetotinayuangao
authored andcommitted
fix(dialog): leaking MdDialogContainer references (#2944)
* fix(dialog): leaking MdDialogContainer references Fixes an issue that caused the `MdDialogContainer` references to not be cleaned up, and as a result, any of the `MdDialogRef` and `MdDialogConfig` instances as well. The issue seems to come from the fact that a couple of blocks that look like: ``` this._ngZone.onMicrotaskEmpty.first().subscribe(() => { this._elementFocusedBeforeDialogWasOpened = document.activeElement; this._focusTrap.focusFirstTabbableElement(); }); ``` End up being transpiled to: ``` var _this = this; this._ngZone.onMicrotaskEmpty.first().subscribe(function () { _this._elementFocusedBeforeDialogWasOpened = document.activeElement; _this._focusTrap.focusFirstTabbableElement(); }); ``` This seems to cause the browser to retain the `_this` reference after the dialog has been destroyed. Fixes #2876. * chore: add comment about `this` usage in zone
1 parent 07bc4ad commit 8e6720b

File tree

1 file changed

+8
-9
lines changed

1 file changed

+8
-9
lines changed

src/lib/dialog/dialog-container.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,8 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
118118
// If were to attempt to focus immediately, then the content of the dialog would not yet be
119119
// ready in instances where change detection has to run first. To deal with this, we simply
120120
// wait for the microtask queue to be empty.
121-
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
122-
this._elementFocusedBeforeDialogWasOpened = document.activeElement as HTMLElement;
123-
this._focusTrap.focusFirstTabbableElement();
124-
});
121+
this._elementFocusedBeforeDialogWasOpened = document.activeElement as HTMLElement;
122+
this._focusTrap.focusFirstTabbableElementWhenReady();
125123
}
126124

127125
/**
@@ -150,16 +148,17 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
150148
// the dialog was opened. Wait for the DOM to finish settling before changing the focus so
151149
// that it doesn't end up back on the <body>. Also note that we need the extra check, because
152150
// IE can set the `activeElement` to null in some cases.
153-
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
154-
let toFocus = this._elementFocusedBeforeDialogWasOpened as HTMLElement;
151+
let toFocus = this._elementFocusedBeforeDialogWasOpened as HTMLElement;
155152

156-
// We need to check whether the focus method exists at all, because IE seems to throw an
157-
// exception, even if the element is the document.body.
153+
// We shouldn't use `this` inside of the NgZone subscription, because it causes a memory leak.
154+
let animationStream = this._onAnimationStateChange;
155+
156+
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
158157
if (toFocus && 'focus' in toFocus) {
159158
toFocus.focus();
160159
}
161160

162-
this._onAnimationStateChange.complete();
161+
animationStream.complete();
163162
});
164163

165164
if (this._focusTrap) {

0 commit comments

Comments
 (0)