Skip to content

Commit 0b0b56c

Browse files
committed
fixup! feat(material-experimental): MDC-based version of dialog
Fix changed after checked expression w/ form-field focus host bindings
1 parent ac0f1c5 commit 0b0b56c

File tree

6 files changed

+36
-18
lines changed

6 files changed

+36
-18
lines changed

src/material-experimental/mdc-dialog/dialog-container.ts

-4
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,6 @@ export class MatDialogContainer extends _MatDialogContainerBase implements
7676
}
7777

7878
ngAfterViewInit() {
79-
// Delegate to the after view init method from the base dialog container. This
80-
// will capture the previously focused element (for later restoring), and will
81-
// set focus to the dialog container (assuming that the container is focusable).
82-
super.ngAfterViewInit();
8379
// Note: Usually we would be able to use the MDC dialog foundation here to handle
8480
// the dialog animation for us, but there are a few reasons why we just leverage
8581
// their styles and not use the runtime foundation code:

src/material-experimental/mdc-dialog/dialog.spec.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,8 @@ describe('MDC-based dialog', () => {
336336
let container =
337337
overlayContainerElement.querySelector('mat-mdc-dialog-container') as HTMLElement;
338338
dispatchKeyboardEvent(document.body, 'keydown', A);
339-
dispatchKeyboardEvent(document.body, 'keydown', A, undefined, backdrop);
340-
dispatchKeyboardEvent(document.body, 'keydown', A, undefined, container);
339+
dispatchKeyboardEvent(backdrop, 'keydown', A);
340+
dispatchKeyboardEvent(container, 'keydown', A);
341341

342342
expect(spy).toHaveBeenCalledTimes(3);
343343
}));
@@ -1055,6 +1055,7 @@ describe('MDC-based dialog', () => {
10551055

10561056
tick(500);
10571057
viewContainerFixture.detectChanges();
1058+
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
10581059

10591060
const backdrop = overlayContainerElement
10601061
.querySelector('.cdk-overlay-backdrop') as HTMLElement;
@@ -1089,6 +1090,7 @@ describe('MDC-based dialog', () => {
10891090

10901091
tick(500);
10911092
viewContainerFixture.detectChanges();
1093+
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
10921094

10931095
const closeButton = overlayContainerElement
10941096
.querySelector('button[mat-dialog-close]') as HTMLElement;
@@ -1125,6 +1127,7 @@ describe('MDC-based dialog', () => {
11251127

11261128
tick(500);
11271129
viewContainerFixture.detectChanges();
1130+
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
11281131

11291132
const closeButton = overlayContainerElement
11301133
.querySelector('button[mat-dialog-close]') as HTMLElement;
@@ -1669,6 +1672,20 @@ describe('MDC-based dialog with animations enabled', () => {
16691672
expect(dialogRef.getState()).toBe(MatDialogState.CLOSED);
16701673
}));
16711674

1675+
it('should attach the focus trap even if automatic focus is disabled', fakeAsync(() => {
1676+
dialog.open(PizzaMsg, {
1677+
viewContainerRef: testViewContainerRef,
1678+
autoFocus: false
1679+
});
1680+
1681+
viewContainerFixture.detectChanges();
1682+
flush();
1683+
1684+
const containerElement = overlayContainer.getContainerElement();
1685+
expect(containerElement.querySelectorAll('.cdk-focus-trap-anchor').length)
1686+
.toBeGreaterThan(0);
1687+
}));
1688+
16721689
it('should re-focus trigger element when dialog closes', fakeAsync(() => {
16731690
// Create a element that has focus before the dialog is opened.
16741691
let button = document.createElement('button');

src/material/dialog/dialog-container.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
} from '@angular/cdk/portal';
1818
import {DOCUMENT} from '@angular/common';
1919
import {
20-
AfterViewInit,
2120
ChangeDetectionStrategy,
2221
ChangeDetectorRef,
2322
Component,
@@ -55,7 +54,7 @@ export function throwMatDialogContentAlreadyAttachedError() {
5554
*/
5655
@Directive()
5756
// tslint:disable-next-line:class-name
58-
export abstract class _MatDialogContainerBase extends BasePortalOutlet implements AfterViewInit {
57+
export abstract class _MatDialogContainerBase extends BasePortalOutlet {
5958
protected _document: Document;
6059

6160
/** The portal outlet inside of this container into which the dialog content will be loaded. */
@@ -100,11 +99,12 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet implement
10099
/** Starts the dialog exit animation. */
101100
abstract _startExitAnimation(): void;
102101

103-
/** If the dialog view completes initialization, the open animation starts. */
104-
ngAfterViewInit() {
102+
/** Initializes the dialog container with the attached content. */
103+
_initializeWithAttachedContent() {
104+
this._setupFocusTrap();
105105
// Save the previously focused element. This element will be re-focused
106106
// when the dialog closes.
107-
this._setupFocusTrap();
107+
this._capturePreviouslyFocusedElement();
108108
// Move focus onto the dialog immediately in order to prevent the user
109109
// from accidentally opening multiple dialogs at the same time.
110110
this._focusDialogContainer();
@@ -206,13 +206,13 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet implement
206206
}
207207
}
208208

209-
/**
210-
* Sets up the focus trap and saves a reference to the
211-
* element that was focused before the dialog was opened.
212-
*/
209+
/** Sets up the focus trap. */
213210
private _setupFocusTrap() {
214211
this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);
212+
}
215213

214+
/** Captures the element that was focused before the dialog was opened. */
215+
private _capturePreviouslyFocusedElement() {
216216
if (this._document) {
217217
this._elementFocusedBeforeDialogWasOpened = this._document.activeElement as HTMLElement;
218218
}

src/material/dialog/dialog.spec.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,6 @@ describe('MatDialog', () => {
11661166

11671167
tick(500);
11681168
viewContainerFixture.detectChanges();
1169-
11701169
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
11711170

11721171
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
@@ -1200,6 +1199,7 @@ describe('MatDialog', () => {
12001199

12011200
tick(500);
12021201
viewContainerFixture.detectChanges();
1202+
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
12031203

12041204
const backdrop = overlayContainerElement
12051205
.querySelector('.cdk-overlay-backdrop') as HTMLElement;
@@ -1235,6 +1235,7 @@ describe('MatDialog', () => {
12351235

12361236
tick(500);
12371237
viewContainerFixture.detectChanges();
1238+
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
12381239

12391240
const closeButton = overlayContainerElement
12401241
.querySelector('button[mat-dialog-close]') as HTMLElement;
@@ -1271,6 +1272,7 @@ describe('MatDialog', () => {
12711272

12721273
tick(500);
12731274
viewContainerFixture.detectChanges();
1275+
expect(lastFocusOrigin!).toBeNull('Expected the trigger button to be blurred');
12741276

12751277
const closeButton = overlayContainerElement
12761278
.querySelector('button[mat-dialog-close]') as HTMLElement;

src/material/dialog/dialog.ts

+3
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ export abstract class _MatDialogBase<C extends _MatDialogContainerBase> implemen
263263
.updateSize(config.width, config.height)
264264
.updatePosition(config.position);
265265

266+
// Notify the dialog container that the content has been attached.
267+
dialogContainer._initializeWithAttachedContent();
268+
266269
return dialogRef;
267270
}
268271

tools/public_api_guard/material/dialog.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export declare abstract class _MatDialogBase<C extends _MatDialogContainerBase>
1414
static ɵfac: i0.ɵɵFactoryDef<_MatDialogBase<any>, never>;
1515
}
1616

17-
export declare abstract class _MatDialogContainerBase extends BasePortalOutlet implements AfterViewInit {
17+
export declare abstract class _MatDialogContainerBase extends BasePortalOutlet {
1818
_animationStateChanged: EventEmitter<DialogAnimationEvent>;
1919
_ariaLabelledBy: string | null;
2020
protected _changeDetectorRef: ChangeDetectorRef;
@@ -28,13 +28,13 @@ export declare abstract class _MatDialogContainerBase extends BasePortalOutlet i
2828
attachDomPortal: (portal: DomPortal) => void;
2929
constructor(_elementRef: ElementRef, _focusTrapFactory: FocusTrapFactory, _changeDetectorRef: ChangeDetectorRef, _document: any,
3030
_config: MatDialogConfig, _focusMonitor?: FocusMonitor | undefined);
31+
_initializeWithAttachedContent(): void;
3132
_recaptureFocus(): void;
3233
protected _restoreFocus(): void;
3334
abstract _startExitAnimation(): void;
3435
protected _trapFocus(): void;
3536
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T>;
3637
attachTemplatePortal<C>(portal: TemplatePortal<C>): EmbeddedViewRef<C>;
37-
ngAfterViewInit(): void;
3838
static ɵdir: i0.ɵɵDirectiveDefWithMeta<_MatDialogContainerBase, never, never, {}, {}, never>;
3939
static ɵfac: i0.ɵɵFactoryDef<_MatDialogContainerBase, [null, null, null, { optional: true; }, null, null]>;
4040
}

0 commit comments

Comments
 (0)