Skip to content

Commit

Permalink
fix(dialog): improved handling of scrollable content
Browse files Browse the repository at this point in the history
* Improves the handling of scrollable content inside the `mat-dialog-content` by using flexbox, rather than a hardcoded `max-height`, to define the content height. This resolves various issues where the dialog would go out of the screen at certain screen sizes or have multiple scrollbars.
* Uses flexbox to ensure that the dialog content elements are always at the appropriate size.

Fixes angular#2481.
Fixes angular#3239.
Fixes angular#6584.
Fixes angular#8493.
  • Loading branch information
crisbeto committed Jul 11, 2018
1 parent afb0ee3 commit 0297e10
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 26 deletions.
40 changes: 36 additions & 4 deletions src/demo-app/dialog/dialog-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ <h1>Dialog demo</h1>
<button mat-raised-button color="accent" (click)="openContentElement()">
Open dialog with content elements
</button>
<button mat-raised-button color="accent" (click)="openTemplate()">
<button mat-raised-button color="accent" (click)="openTemplate(templateDialog)">
Open dialog with template content
</button>
<button mat-raised-button color="accent" (click)="openTemplate(templateDialogWithContent)">
Open template dialog with content elements
</button>


<mat-card class="demo-dialog-card">
<mat-card-content>
Expand Down Expand Up @@ -111,7 +115,7 @@ <h2>Other options</h2>
<p>Last afterClosed result: {{lastAfterClosedResult}}</p>
<p>Last beforeClose result: {{lastBeforeCloseResult}}</p>

<ng-template let-data let-dialogRef="dialogRef">
<ng-template #templateDialog let-data let-dialogRef="dialogRef">
I'm a template dialog. I've been opened {{numTemplateOpens}} times!

<p>It's Jazz!</p>
Expand All @@ -122,6 +126,34 @@ <h2>Other options</h2>
</mat-form-field>

<p> {{ data.message }} </p>
<button type="button" (click)="dialogRef.close(howMuch.value)">Close dialog</button>
<button (click)="dialogRef.updateSize('500px', '500px').updatePosition({ top: '25px', left: '25px' });">Change dimensions</button>`
<button type="button" (click)="dialogRef.close(lastCloseResult = howMuch.value)">Close dialog</button>
<button (click)="dialogRef.updateSize('500px', '500px').updatePosition({ top: '25px', left: '25px' });">Change dimensions</button>
</ng-template>

<ng-template #templateDialogWithContent let-data let-dialogRef="dialogRef">
<h2 mat-dialog-title>Saturn</h2>

<mat-dialog-content>
<img style="max-width: 100%;" src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Saturn_during_Equinox.jpg/1920px-Saturn_during_Equinox.jpg" alt="Saturn">
Saturn is the sixth planet from the Sun and the second-largest in the Solar System, after
Jupiter. It is a gas giant with an average radius about nine times that of Earth. It has
only one-eighth the average density of Earth, but with its larger volume Saturn is over
95 times more massive. Saturn is named after the Roman god of agriculture; its astronomical
symbol (♄) represents the god's sickle.

Saturn's interior is probably composed of a core of iron–nickel and rock
(silicon and oxygen compounds). This core is surrounded by a deep layer of metallic hydrogen,
an intermediate layer of liquid hydrogen and liquid helium, and finally a gaseous outer layer.
Saturn has a pale yellow hue due to ammonia crystals in its upper atmosphere. Electrical
current within the metallic hydrogen layer is thought to give rise to Saturn's planetary
magnetic field, which is weaker than Earth's, but has a magnetic moment 580 times that of
Earth due to Saturn's larger size. Saturn's magnetic field strength is around one-twentieth
of Jupiter's. The outer atmosphere is generally bland and lacking in contrast, although
long-lived features can appear. Wind speeds on Saturn can reach 1,800 km/h (1,100 mph),
higher than on Jupiter, but not as high as those on Neptune.
</mat-dialog-content>

<mat-dialog-actions>
<button mat-raised-button color="primary" (click)="dialogRef.close()">Close dialog</button>
</mat-dialog-actions>
</ng-template>
16 changes: 7 additions & 9 deletions src/demo-app/dialog/dialog-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ export class DialogDemo {
panelClass: 'custom-overlay-pane-class',
hasBackdrop: true,
backdropClass: '',
width: '',
height: '',
minWidth: '',
minHeight: '',
width: defaultDialogConfig.width,
height: defaultDialogConfig.height,
minWidth: defaultDialogConfig.minWidth,
minHeight: defaultDialogConfig.minHeight,
maxWidth: defaultDialogConfig.maxWidth,
maxHeight: '',
maxHeight: defaultDialogConfig.maxHeight,
position: {
top: '',
bottom: '',
Expand All @@ -47,8 +47,6 @@ export class DialogDemo {
};
numTemplateOpens = 0;

@ViewChild(TemplateRef) template: TemplateRef<any>;

constructor(public dialog: MatDialog, @Inject(DOCUMENT) doc: any) {
// Possible useful example for the open and closeAll events.
// Adding a class to the body if a dialog opens and
Expand Down Expand Up @@ -80,9 +78,9 @@ export class DialogDemo {
dialogRef.componentInstance.actionsAlignment = this.actionsAlignment;
}

openTemplate() {
openTemplate(template: TemplateRef<any>) {
this.numTemplateOpens++;
this.dialog.open(this.template, this.config);
this.dialog.open(template, this.config);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/dialog/dialog-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class MatDialogConfig<D = any> {
maxWidth?: number | string = '80vw';

/** Max-height of the dialog. If a number is provided, pixel units are assumed. */
maxHeight?: number | string;
maxHeight?: number | string = '80vh';

/** Position overrides. */
position?: DialogPosition;
Expand Down
4 changes: 3 additions & 1 deletion src/lib/dialog/dialog-container.html
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
<ng-template cdkPortalOutlet></ng-template>
<div class="mat-dialog-component-host">
<ng-template cdkPortalOutlet></ng-template>
</div>
29 changes: 27 additions & 2 deletions src/lib/dialog/dialog-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,15 @@ export class MatDialogContainer extends BasePortalOutlet {
}

this._savePreviouslyFocusedElement();
return this._portalOutlet.attachComponentPortal(portal);

const componentRef = this._portalOutlet.attachComponentPortal(portal);

// We need to add an extra class to the root of the instantiated component, which
// allows us to propagate some width/height overrides down from the overlay pane.
componentRef.location.nativeElement.classList.add('mat-dialog-component-host');
this._toggleScrollableContentClass();

return componentRef;
}

/**
Expand All @@ -126,7 +134,9 @@ export class MatDialogContainer extends BasePortalOutlet {
}

this._savePreviouslyFocusedElement();
return this._portalOutlet.attachTemplatePortal(portal);
const viewRef = this._portalOutlet.attachTemplatePortal(portal);
this._toggleScrollableContentClass();
return viewRef;
}

/** Moves the focus inside the focus trap. */
Expand Down Expand Up @@ -196,4 +206,19 @@ export class MatDialogContainer extends BasePortalOutlet {
// view container is using OnPush change detection.
this._changeDetectorRef.markForCheck();
}

/**
* Toggles a class on the host element, depending on whether it has
* scrollable content. Used to activate particular flexbox styling.
*/
private _toggleScrollableContentClass() {
const element: HTMLElement = this._elementRef.nativeElement;
const cssClass = 'mat-dialog-container-scrollable';

if (element.querySelector('.mat-dialog-content')) {
element.classList.add(cssClass);
} else {
element.classList.remove(cssClass);
}
}
}
52 changes: 43 additions & 9 deletions src/lib/dialog/dialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@


$mat-dialog-padding: 24px !default;
$mat-dialog-title-padding: 24px !default;
$mat-dialog-border-radius: 2px !default;
$mat-dialog-max-height: 65vh !default;
$mat-dialog-button-margin: 8px !default;

// TODO(crisbeto): not used anywhere, to be removed next major release.
$mat-dialog-max-height: 65vh !default;

.mat-dialog-container {
@include mat-elevation(24);

Expand All @@ -32,27 +35,58 @@ $mat-dialog-button-margin: 8px !default;
}
}

.mat-dialog-container-scrollable {
padding: 0;

// Since there are 5-6 levels of elements down before we can reach
// the projected content, we have to use a class that lets us propagate
// the dimensions down to the relevant flexboxes, in order for IE to
// work correctly.
&, .mat-dialog-component-host {
width: inherit;
min-width: inherit;
max-width: inherit;
height: inherit;
min-height: inherit;
max-height: inherit;
display: flex;
flex-direction: column;
overflow: auto;
}
}

.mat-dialog-title {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
flex-shrink: 0;
margin: 0;
padding: $mat-dialog-title-padding;
box-sizing: border-box;
}

.mat-dialog-content {
display: block;
margin: 0 $mat-dialog-padding * -1;
padding: 0 $mat-dialog-padding;
max-height: $mat-dialog-max-height;
padding: $mat-dialog-padding $mat-dialog-padding 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
}

.mat-dialog-title {
margin: 0 0 20px;
display: block;
// Avoid stacking the padding if there's a title.
.mat-dialog-title ~ & {
padding-top: 0;
}
}

.mat-dialog-actions {
padding: $mat-dialog-padding / 2 0;
padding: $mat-dialog-padding / 2 $mat-dialog-padding;
display: flex;
flex-wrap: wrap;

// Pull the actions down to avoid their padding stacking with the dialog's padding.
margin-bottom: -$mat-dialog-padding;
align-items: center;
flex-shrink: 0;

&[align='end'] {
justify-content: flex-end;
Expand Down
14 changes: 14 additions & 0 deletions src/lib/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,13 @@ describe('MatDialog', () => {
}));

runContentElementTests();

it('should set the `mat-dialog-component-host` class on the rendered component', () => {
const container = overlayContainerElement.querySelector('mat-dialog-container')!;
const host = container.querySelector('content-element-dialog')!;

expect(host.classList).toContain('mat-dialog-component-host');
});
});

describe('inside template portal', () => {
Expand Down Expand Up @@ -1093,6 +1100,11 @@ describe('MatDialog', () => {
expect(container.getAttribute('aria-labelledby'))
.toBe(title.id, 'Expected the aria-labelledby to match the title id.');
}));

it('should set the `mat-dialog-container-scrollable` class on the container', () => {
const container = overlayContainerElement.querySelector('mat-dialog-container')!;
expect(container.classList).toContain('mat-dialog-container-scrollable');
});
}
});

Expand Down Expand Up @@ -1343,6 +1355,7 @@ class PizzaMsg {
}

@Component({
selector: 'content-element-dialog',
template: `
<h1 mat-dialog-title>This is the title</h1>
<mat-dialog-content>Lorem ipsum dolor sit amet.</mat-dialog-content>
Expand All @@ -1360,6 +1373,7 @@ class PizzaMsg {
class ContentElementDialog {}

@Component({
selector: 'content-element-dialog',
template: `
<ng-template>
<h1 mat-dialog-title>This is the title</h1>
Expand Down

0 comments on commit 0297e10

Please sign in to comment.