Angular2 RC 5.没有为动态加载的组件找到组件工厂



我试图更新我的动态组件加载器从RC4到RC5,因为ComponentResolver已弃用。我已经将加载器更新为以下

@Component({
    selector: 'component-dispatcher',
    template: `<div #container></div>` // Define the template here because of its brevity
})
export class ComponentDispatcherComponent implements OnInit, OnDestroy {
    @Input() component:any; // Some dynamic component to render
    @Input() options:any;   // Component configuration, optional
    @Input() data:any;      // Data to render within the component
    // Inject the dynamic component onto the DOM
    @ViewChild("container", {read: ViewContainerRef}) container:ViewContainerRef;
    private componentReference:ComponentRef<any>;
    constructor(private resolver:ComponentFactoryResolver) {
    }
    ngOnInit() {
        // Create our component now we're initialised
        let componentFactory = this.resolver.resolveComponentFactory(this.component);
        this.componentReference = this.container.createComponent(componentFactory);
        this.componentReference.instance.data = this.data;
        this.componentReference.instance.options = this.options;
    }
    ngOnDestroy() {
        // If we have a component, make sure we destroy it when we lose our owner
        if (this.componentReference) {
            this.componentReference.destroy();
        }
    }
}
并尝试将以下组件动态加载到DOM 中
@Component({
    selector: 'text-cell',
    pipes: [IterableObjectPipe],
    templateUrl: './text-cell.component.html',
    styles: ['.fieldName { font-weight: bold; }']
})
export class TextCellComponent implements OnInit {
    // Data to render within the component
    @Input() data: any;
    @Input() record: any;
    // Configuration of what data to display
    @Input() options: {
        excludeFieldNames: boolean,
        translation: string
    };
    constructor() {
    }
    ngOnInit() {
        setTimeout(() => {
            //console.log('***************************** ngOnInit...textCell ***********************');
            this.options.translation = '' + (_.get(this.options, 'translation') || 'fields');
        });
    }
}

然而,当我这样做与我的TextCellComponent或任何其他组件在应用程序中,我得到以下错误

ORIGINAL EXCEPTION: No component factory found for TextCellComponent
ORIGINAL STACKTRACE:
Error: No component factory found for TextCellComponent
at NoComponentFactoryError.BaseException [as constructor]      
(webpack:///./~/@angular/core/src/facade/exceptions.js?:27:23)
at new NoComponentFactoryError 

我已经完成了

中的步骤
https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html

但我似乎错过了什么。我试过将组件添加到引导并全局定义它们,但没有运气。任何建议都会很有帮助。

编辑

添加模块定义

@NgModule({
    imports: [
        BrowserModule, 
        HttpModule, 
        FormsModule, 
        ReactiveFormsModule, 
        ...MATERIAL_MODULES
    ],
    declarations: [
        ...APPLICATION_PIPES, 
        ...APPLICATION_COMPONENTS, 
        ...APPLICATION_DIRECTIVES, 
        CygnusComponent,
        // Component declarations
        // TODO: refactor to appropriate modules
        ...
        ComponentDispatcherComponent,
        TextCellComponent,
        ...
    ],
    bootstrap: [
        ApplicationComponent
    ],
    providers: [
        ...APPLICATION_PROVIDERS, 
        AppStore
    ]
})
export class ApplicationComponent {}

所有将要"动态"加载的组件都需要在模块的entryComponents部分声明。换句话说,你应该像这样结束:

@NgModule({
    imports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule, ...MATERIAL_MODULES],
    declarations: [...APPLICATION_PIPES, ...APPLICATION_COMPONENTS, ...APPLICATION_DIRECTIVES, CygnusComponent,
        // Component declarations
        // TODO: refactor to appropriate modules
        ...
        ComponentDispatcherComponent,
        TextCellComponent,
        ...
    entryComponents: [TextCellComponent]
    bootstrap: [ApplicationComponent],
    providers: [...APPLICATION_PROVIDERS, AppStore]
})
export class ApplicationComponent{

请注意,您需要在 declarations entryComponents部分中列出TextCellComponent

您可能需要检查您的导入路径。在我的例子中,一个文件导入使用大写,而另一个使用小写。

//file 1
import { IRComponent } from "./components/IR/IR.component";
//file 2
import { IRComponent } from "./components/ir/ir.component";

泄露在Chrome网络选项卡中,我注意到文件被加载了两次(每个拼写一次)。

假设TextCellComponentFooModule中声明,而负责创建动态内容的组件在模块BarModule中。

在这种情况下,需要将FooModule导入BarModule

@NgModule({
 imports: [FooModule],
declarations: [ComponentDispatcherComponent]
})
export class BarModule {}

在我看来,这有点违背了动态的想法。我只是想要一个组件,它将创建我通过类引用发送给的任何组件。如果谁有好的解决办法,我很乐意听听。

有时你会遇到这个问题,即使你已经在EntryComponents和Declarations中给出了组件。

在这种情况下,你只需要在所有其他组件上面输入这个组件名称(这里是TextCellComponent),如下所示:

declarations: [ 
        TextCellComponent // Declared above
        CygnusComponent,
        ComponentDispatcherComponent,
        ...
    ]

这也应该在entryComponents中完成。

希望对你有帮助。

您需要在Module中导入MatDialogModule,以便它知道那里的entryComponents

相关内容

最新更新