angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.39k stars 6.76k forks source link

feat(dialog): Ability to present MatDialog fullscreen #10094

Open asido opened 6 years ago

asido commented 6 years ago

Bug, feature request, or proposal:

feature request

What is the expected behavior?

An ability to present modal dialogs fullscreen.

What is the current behavior?

Can't present modal dialogs fullscreen.

What are the steps to reproduce?

What is the use-case or motivation for changing an existing behavior?

This feature is in Material design specifications: https://material.io/guidelines/components/dialogs.html#dialogs-full-screen-dialogs

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Is there anything else we should know?

crisbeto commented 6 years ago

You should be able to make a dialog fullscreen by setting its width and maxWidth to 100vw.

asido commented 6 years ago

Width works fine, but the height doesn't.

I forked the "What's your name?" dialog sample, added width and height overflowing content and set maxWidth/maxHeight to 100vw/100vh: See here

The maxHeight is hardcoded in the library to be 65vh. I believe it's due to mobile devices, where 100vh always overflows the visible document?

You can go ahead and set height:100vh, but that will simply stretch the frame, while the content will overflow at 65vh.

crisbeto commented 6 years ago

That's a general issue with the dialog that'll go away with https://github.com/angular/material2/pull/9236. Until then you should be able to work around it by overriding it in your CSS.

jtcrowson commented 6 years ago

Would be nice to be able to configure full screen when width < 600 px (on mobile).

engineer-andrew commented 6 years ago

I came across this issue while looking specifically for a way to open a dialog full screen only on small devices. This seems like something that gets asked a lot so I wrote a blog post about it and provided my solution there.

Essentially what we can do is resize the open dialog when the device size changes by using the BreakpointObserver class. You have to know the size you want to use on large screens, but other than that I haven't found any problems with it.

Hope this helps someone else.

@jtcrowson I think what I wrote up solves your problem and it's pretty easy to implement.

simeyla commented 6 years ago

@jtcrowson Here's my solution

First of all - as an aside - we need to stop using 100vh. Forget it even exists for the purposes of dialogs. It flat out doesn't work well on mobile devices with toolbars that hide once you start scrolling and can correspond to a height that's taller than the actual visible viewport. What's great about the overlay API is it sticks everything in a DIV anchored on top of the whole site, so using calc(100% - 2em) works very well.

What I'm doing is taking advantage of the fact that MatDialog allows you to add css classes for the overlay and panel. When you open a dialog you add these parameters to 'options':

    {
            backdropClass: 'logindialog-overlay',
            panelClass: 'logindialog-panel'
    }

Then the following css is used to change the size of the dialog when on mobile and make it fullscreen.

.logindialog-overlay
{
    .mobile &
    {
        background: black;
    }
}

.logindialog-panel
{
    .mobile &
    {
        // important is used because MatDialog applies css to the elements
        max-width: none !important;
        max-height: none !important;

        width: calc(100% - 2em) !important;
        height: calc(100% - 2em) !important;
    }
}

You can choose to just use media queries to enable this (and remove the .mobile class) - but this is Angular and we're smarter than that and we're probably using something like Anglar Flex Layout

So what is .mobile you are probably asking? Well it's a class that I am applying to the overlay container element - so as to give me a 'modernizr' style css parent class I can then 'consume'. I do this inside my LoginDialogComponent.


    constructor(
        public dialogRef: MatDialogRef<LoginDialogComponent>,
        private renderer: Renderer2,
        private smartLayout: SmartLayoutService,
        public overlayC: OverlayContainer,

        @Inject(MAT_DIALOG_DATA) public data: ILoginDialogData) {

            // reference to container element where the overlays get added to
            const overlay = overlayC.getContainerElement();

            smartLayout.getObservable('mobile').subscribe((isMobile) => {

                if (isMobile){
                    renderer.addClass(overlay, 'mobile');
                } else {
                    renderer.removeClass(overlay, 'mobile');
                }
            });
    }

SmartLayout is my extension to FlexLayout that uses MediaMonitor to monitor for changes to media queries.

nicoraffin commented 5 years ago

Here's my solution. What about a PopupService?

------------------ popup.service.ts ------------------

import { Injectable, TemplateRef } from '@angular/core';
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
import { MatDialogRef, MatDialog, MatDialogConfig } from '@angular/material';
import { ComponentType } from '@angular/cdk/portal';

@Injectable({
providedIn: 'root'
})

export class PopupService {

constructor(private dialog: MatDialog, private breakpointObserver: BreakpointObserver) { }

matDialogRef: any;
smallDialogSubscription: any;

open(componentOrTemplateRef: ComponentType | TemplateRef, mobileWidth: string, data?: MatDialogConfig): MatDialogRef {
if (data) {
data.maxWidth = '100vw';
data.maxHeight = '100vh';
}

this.matDialogRef = this.dialog.open(componentOrTemplateRef, data);

this.smallDialogSubscription = this.breakpointObserver.observe([Breakpoints.XSmall, Breakpoints.Small])
.subscribe(size => {
if (size.matches) {
this.matDialogRef.updateSize('100%', '100%');
} else {
this.matDialogRef.updateSize(mobileWidth, 'auto');
}
});

return this.matDialogRef;
}

close(): void {
this.smallDialogSubscription.unsubscribe();
this.matDialogRef.close();
}

}

--------- account.component.ts --------

...
editAccount() {
this.popupservice.open(AccountEditComponent, '800px', {
data: {}
});
}
...

--------- account-edit.component.ts --------

...
close() {
this.popupservice.close();
}
...

Based on this blog

Tibo46 commented 5 years ago

You can do it in pure CSS .cdk-overlay-pane { width: 90%; height: 90%; } @media(max-width: 1000px) { .cdk-overlay-pane { width: 100%; height: 100%; } }

and just don't put the width and height when instantiating your modal (you can pass max width and height) const dialogRef = this.dialog.open(AvailableRoomsComponent, { maxWidth: '100vw', maxHeight: '100vh' });

aehven commented 5 years ago

I got it working with this in css:

.cdk-overlay-pane {
  max-width: 95vw !important;
}

But then I still have to add size to my dialog creation to take advantage of that:

let dialogRef = this.dialog.open(MyDialogComponent, {width: '100vw', data: {blah}});
makamekm commented 5 years ago

It works using:

const dialogRef = this.dialog.open(AvailableRoomsComponent, {
  minWidth: '100vw',
  height: '100vh'
});
kjdeepak commented 5 years ago

@makamekm Awesome. You saved my day! This technique works perfectly.

wutzebaer commented 4 years ago

just wanted to drop my workaround-hack, in case the above doesn't work for you, like me, i used the mat-content tag to keep my buttons in view

  .cdk-overlay-pane {
    max-width: none !important;
    flex: 1 1 100%;
    height: 100%;
  }
  .mat-dialog-content {
    max-height: none !important;
    flex: auto;
  }
phrei commented 4 years ago

It's a good workaround but it's not really a full-screen dialog as specified by Material Design - (find "Full-screen dialog") i.E. the closing "X" on the top left and "save" button on the top right.

Wildhammer commented 4 years ago

The workarounds only take care of the size, the action buttons layout is different in the material guidelines. They are at the top.

Screen Shot 2020-05-05 at 2 29 31 PM
faan11 commented 4 years ago

For my project, I did this feature module to manage dynamic dialog layout.

The module has four functions:

If you only need to present the dialog in fullscreen mode, you can search in the first two functions.

https://gist.github.com/faan11/7eb04a23e6d63d1a0a95260c8211dec5

Char2sGu commented 2 years ago

As the dialog component in Angualr Material Experimantal has adopted the implementation from MDC, where full-screen dialog is available, I believe it is super easy for the team to implement this feature, but they didn't 😕.

jpike88 commented 1 year ago

I don't understand how this wasn't implemented from the beginning. Who wants to look at a tiny box inside a tiny box, which is their mobile phone screen? Doesn't it make sense to place dialog buttons down the bottom centre in a vertical row for people to easily use their thumb, instead of stabbing around the middle of the screen?

For all of the effort poured into Material Design these kinds of considerations seem so basic, and I still have to twist the dialog's styling and button placement to achieve some basic usability standards.

lgicc commented 3 months ago

Is there any progress in this? I would really enjoy this feature too, so the app would be much more mobile friendly :)