Search code examples
angularangular-materialmodal-dialogangular-upgrade

After Angular 5->8 upgrade, Material dialogs show up in DOM, but do not render on screen


After completing an upgrade from Angular 5 to 8, almost everything works, except the Material modal dialogs. Using the browser debugger, we can see that the structure is in the DOM, but they don't get drawn. We were using the No-op animator module originally. When I switched it to the BrowserAnimations module, the dialog would appear for the animation, but once the animation was complete, it disappeared visually. It's still there and you can partially interact with it -- if you click where the Close button should be rendered, the dialog will close. (You can tell this because the "glass"/grey screen cover goes away.) We've fixed all of the unit tests (2500+) and they run 100% clean and most of the application works as expected. It's just that the dialogs disappear visually.

Things I've tried already:

  1. setting the z-index of various items to ridiculous values (25000) via the Chrome debugging tools
  2. setting CSS display properties explicitly to "block" on a variety of elements through the debugger
  3. setting CSS visibility explicitly to "visible"
  4. setting CSS opacity explicitly to "1"
  5. verified that the dialog components are all listed in the EntryComponents of the module that they are in (and that this module is imported into the main app module)

Everything worked fine with Angular 5 -- it's definitely a side-effect of the upgrade. I suspect that this may be an interaction of Material with some other module we're using that used to play nice together, but no longer do. However, I'm not sure what that might be or how to figure it out. To that end, here's what we're using (package.json extact):

  "dependencies": {
    "@angular/animations": "^8.2.1",
    "@angular/cdk": "^8.1.2",
    "@angular/common": "^8.2.1",
    "@angular/compiler": "^8.2.1",
    "@angular/core": "^8.2.1",
    "@angular/flex-layout": "^8.0.0-beta.27",
    "@angular/forms": "^8.2.1",
    "@angular/material": "^8.1.2",
    "@angular/material-moment-adapter": "^8.1.2",
    "@angular/platform-browser": "^8.2.1",
    "@angular/platform-browser-dynamic": "^8.2.1",
    "@angular/router": "^8.2.1",
    "@ngx-translate/core": "^11.0.1",
    "@ngx-translate/http-loader": "^4.0.0",
    "bootstrap": "^4.3.1",
    "classlist.js": "^1.1.20150312",
    "core-js": "^3.2.1",
    "hammerjs": "^2.0.8",
    "jwt-decode": "^2.2.0",
    "moment": "^2.24.0",
    "ngx-bootstrap": "^5.1.1",
    "pdfjs-dist": "^2.1.266",
    "rxjs": "^6.5.2",
    "ts-helpers": "^1.1.2",
    "tslib": "^1.10.0",
    "velocity-animate": "^1.5.2",
    "web-animations-js": "^2.3.2",
    "zone.js": "~0.9.1"
  },

In my app.module.ts I have the following:

@NgModule({
    imports: [
        <<<snip>>> ModalTemplatesModule, 
        BrowserAnimationsModule, <<<snip>>>    ],

And then the ModalTemplatesModule is defined as:

const modalTemplates: any[] = [
    ModalTimeoutComponent,
    ConfirmActionModalComponent,
    // etc...
];

@NgModule({
    imports: [
        SharedModule,
        ReactiveFormsModule,
        FormsModule,
        CommonComponentsModule,
        CommonNonComponentsModule
    ],
    declarations: modalTemplates,
    exports: modalTemplates,
    providers: [
        ConfigService,
        TransactionService
    ],
    entryComponents: modalTemplates
})
export class ModalTemplatesModule {}

We did create a wrapper for all of our modals that we then the specific dialog contents into. So if something is wrong with the code, it's likely in this class. But it's pretty simple... ModalWrapper template:

<div fxLayoutAlign="center center" fxLayout="column" fxFlexFill>
    <div class="modal-wrapper full-width" fxLayout="column" fxLayoutAlign="center center">
        <div *ngIf="showCloseButton" class="full-width" fxLayoutAlign="end end" fxLayout="column" fxFlex="none">
            <button id="closeButton" class="close-button-outside" (click)="close()" #closeButton>
            <span fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="0.5rem">
                <i class="icon-close-hover"></i>
                <span>{{"common.buttons.close" | translate}}</span>
            </span>
            </button>
        </div>
        <ng-content></ng-content>
    </div>
</div>

The actual tag is within the templates of the component that is placed in the wrapper via .

ModalWrapperComponent

@Component({
    selector : 'modal-wrapper',
    templateUrl: './modal-wrapper.component.html',
    styleUrls: ['./modal-wrapper.component.scss']
})
export class ModalWrapperComponent {
    @Output() onClose: EventEmitter<void> = new EventEmitter<void>();
    @Input() showCloseButton: boolean = true;

    constructor() {}

    close(): void {
        this.onClose.emit();
    }
}

At this point, I'm running out of ideas for why it disappears and how to fix it. Hoping that somebody else encountered this and recognizes the problem and knows how to fix it!

Update: If I use the WAVE accessibility plug-in for Chrome and "disable all CSS", the dialog elements do appear at the bottom of the screen. So that would suggest that it's a style-related issue. Is there any other way to "hide" something??


Solution

  • Finally figured it out. In our Angular 5 code, we had a material-overrides.scss file. In it, somebody had added the following style:

    mat-dialog-container {
      opacity: 0;
      @include transform(translate3d(0, 3.5rem, 0));
      @include transition(opacity $animation-time, -webkit-transform $animation-time);
    }
    

    When I commented out the opacity: 0, my dialogs started to appear. Not sure why we had this in Angular 5 (material 2.0.0-beta). Didn't seem to cause any issues then, but it did now. Anyway, problem solved.