Skip to content

Commit

Permalink
fix(dialog): leaking MdDialogContainer references
Browse files Browse the repository at this point in the history
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 angular#2876.
  • Loading branch information
crisbeto committed Feb 5, 2017
1 parent f8c8e7f commit edc342d
Showing 1 changed file with 7 additions and 10 deletions.
17 changes: 7 additions & 10 deletions src/lib/dialog/dialog-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
ViewEncapsulation,
NgZone,
OnDestroy,
Renderer,
} from '@angular/core';
import {BasePortalHost, ComponentPortal, PortalHostDirective, TemplatePortal} from '../core';
import {MdDialogConfig} from './dialog-config';
Expand Down Expand Up @@ -47,7 +46,7 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
/** Reference to the open dialog. */
dialogRef: MdDialogRef<any>;

constructor(private _ngZone: NgZone, private _renderer: Renderer) {
constructor(private _ngZone: NgZone) {
super();
}

Expand All @@ -65,10 +64,8 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
// If were to attempt to focus immediately, then the content of the dialog would not yet be
// ready in instances where change detection has to run first. To deal with this, we simply
// wait for the microtask queue to be empty.
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
this._elementFocusedBeforeDialogWasOpened = document.activeElement;
this._focusTrap.focusFirstTabbableElement();
});
this._elementFocusedBeforeDialogWasOpened = document.activeElement;
this._focusTrap.focusFirstTabbableElementWhenReady();

return attachResult;
}
Expand All @@ -93,10 +90,10 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
// the dialog was opened. Wait for the DOM to finish settling before changing the focus so
// that it doesn't end up back on the <body>. Also note that we need the extra check, because
// IE can set the `activeElement` to null in some cases.
if (this._elementFocusedBeforeDialogWasOpened) {
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
this._renderer.invokeElementMethod(this._elementFocusedBeforeDialogWasOpened, 'focus');
});
let toFocus = this._elementFocusedBeforeDialogWasOpened as HTMLElement;

if (toFocus && 'focus' in toFocus) {
this._ngZone.onMicrotaskEmpty.first().subscribe(() => toFocus.focus());
}
}
}

0 comments on commit edc342d

Please sign in to comment.