Components: MdDialog: Declaring MyDialogComponent in lazy-loaded module breaks app

Created on 4 Jan 2017  路  12Comments  路  Source: angular/components

Bug, feature request, or proposal:

Bug

What is the expected behavior?

  1. I declare MyDialogComponent in sub-module in declarations: [MyDialogComponent] and entryComponents: [MyDialogComponent]
  2. I open MyDialogComponent with this.dialog.open(MyDialogComponent);
  3. I see MyDialogComponent as a dialog open up.

What is the current behavior?

Running step 2 I get the following error:

error_handler.js:50 EXCEPTION: Error in ./HistoryComponent class HistoryComponent - inline template:12:28 caused by: No component factory found for MyDialogComponent. Did you add it to @NgModule.entryComponents?
error_handler.js:52 ORIGINAL EXCEPTION: No component factory found for MyDialogComponent. Did you add it to @NgModule.entryComponents?

I have clearly added it to the sub-modules declarations and entryComponents.

// --- module.ts --- //
@NgModule({
    imports: [
        SharedModule,
        MdDialogModule,
    ],
    exports: [],
    declarations: [
        HistoryComponent,
        MyDialogComponent,
    ],
    providers: [],
    entryComponents: [
        MyDialogComponent
    ]
})
export class HistoryModule { }

// --- component.ts --- //
import { Component } from '@angular/core';
import { MdDialog, MdDialogRef } from '@angular/material/dialog';
import { MyDialogComponent } from './my-dialog.component';

@Component({
    selector: 'app-history',
    templateUrl: './history.component.html',
    styleUrls: ['./history.component.scss']
})
export class HistoryComponent {

    dialogRef: MdDialogRef<MyDialogComponent>;

    constructor(
        private dialog: MdDialog
    ) { }

    showDialog() {
        this.dialogRef = this.dialog.open(MyDialogComponent, {
            disableClose: false
        });

        this.dialogRef.afterClosed().subscribe(result => {
            console.log('result', result);
            this.dialogRef = null;
        });
    }
}

The interesting thing is, that when I add and declare the MyDialogComponent in the main app.module.ts the dialog opens up just fine.

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

angular-cli: 1.0.0-beta.24
node: 6.7.0
os: linux x64
@angular/common: 2.4.1
@angular/compiler: 2.4.1
@angular/core: 2.4.1
@angular/forms: 2.4.1
@angular/http: 2.4.1
@angular/material: 2.0.0-beta.1
@angular/platform-browser: 2.4.1
@angular/platform-browser-dynamic: 2.4.1
@angular/router: 3.1.1
@angular/compiler-cli: 2.4.1

Most helpful comment

@ciesielskico Are you using lazy loading for your submodule? I am running into the exact same problem, but only when using lazy loading.

All 12 comments

+1

@ciesielskico Are you using lazy loading for your submodule? I am running into the exact same problem, but only when using lazy loading.

+1024 @ciesielskico Just in using lazy loading!馃槀

+1

Just ran into this myself. For me it's game-breaking as I am working on a large application which _only_ has content in lazy-loaded submodules!

Workaround is to declare the dialog components in app module.

Yep that is a possible workaround for some use cases but unfortunately not mine (internal workflow app with separate lazy-loaded modules for different teams).

The issue as far as I can see is that the MdDialog service employes a PortalHostDirective to inject dynamic content into the DOM. This directive in turn uses an injected instance of ComponentFactoryResolver to resolve the component token it has been asked to instantiate. But since PortalHostDirective is eagerly loaded (i.e. loaded when the main app module is bootstrapped), this resolver does not include the components of the lazy-loaded module.

I guess a fix therefore involves forcing the PortalHostDirective to use a resolver that corresponds to the context in which it is used, so that it will have the same view of which components exist as the component that requested the dialog in the first place.

I've implemented a hacky workaround here: https://github.com/benelliott/material2/tree/dialog-lazyload-workaround

It exposes an optional resolver option in MdDialogConfig so that you can pass the calling component's ComponentFactoryResolver into the dialog when the component is to be dynamically instantiated (also modifies ComponentPortal etc accordingly).

I don't like the idea of forcing the user to deal with this in this way so this is far from a pull request - just a prompt for discussion until a full fix arrives.

Yes, this is a duplicate and should be closed. There is a workaround using the latest master mentioned here: https://github.com/angular/material2/issues/1765#issuecomment-272232271

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

crutchcorn picture crutchcorn  路  3Comments

jelbourn picture jelbourn  路  3Comments

constantinlucian picture constantinlucian  路  3Comments

vanor89 picture vanor89  路  3Comments

theunreal picture theunreal  路  3Comments