使用来自另一个模块的组件

Use component from another module

我使用 angular-cli 生成了 Angular 2.0.0 应用程序。

当我创建一个组件并将其添加到 AppModule 的声明数组时,一切都很好,可以正常工作。

我决定把组件分开,所以我创建了一个TaskModule和一个组件TaskCard。现在我想在 AppModuleBoard 组件)的组件之一中使用 TaskCard

应用模块:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { BoardComponent } from './board/board.component';
import { LoginComponent } from './login/login.component';

import { MdButtonModule } from '@angular2-material/button';
import { MdInputModule } from '@angular2-material/input';
import { MdToolbarModule } from '@angular2-material/toolbar';

import { routing, appRoutingProviders} from './app.routing';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

import { UserService  } from './services/user/user.service';
import { TaskModule } from './task/task.module';


@NgModule({
  declarations: [
    AppComponent,
    BoardComponent,// I want to use TaskCard in this component
    LoginComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    MdButtonModule,
    MdInputModule,
    MdToolbarModule,
    routing,
    TaskModule // TaskCard is in this module
  ],
  providers: [UserService],
  bootstrap: [AppComponent]
})
export class AppModule { }

任务模块:

import { NgModule } from '@angular/core';
import { TaskCardComponent } from './task-card/task-card.component';

import { MdCardModule } from '@angular2-material/card';

@NgModule({
  declarations: [TaskCardComponent],
  imports: [MdCardModule],
  providers: []
})
export class TaskModule{}

整个项目在 https://github.com/evgdim/angular2(看板文件夹)

上可用

我错过了什么?我需要做什么才能在 BoardComponent 中使用 TaskCardComponent

这里的主要规则是:

组件模板编译期间适用的选择器由声明该组件的模块以及该模块导入的导出的传递闭包决定。

所以,尝试导出它:

@NgModule({
  declarations: [TaskCardComponent],
  imports: [MdCardModule],
  exports: [TaskCardComponent] // <== export the component you want to use in another module
})
export class TaskModule{}

我应该导出什么?

Export declarable classes that components in other modules should be able to reference in their templates. These are your public classes. If you don't export a class, it stays private, visible only to other component declared in this module.

在你创建一个新模块的那一刻,无论是否是惰性的,任何新模块并且你在其中声明任何东西,那个新模块都有一个干净的状态(正如 Ward Bell 在 https://devchat.tv/adv-in-angular/119-aia-avoiding-common-pitfalls-in-angular2 中所说)

Angular 为每个 @NgModule 创建 传递模块

此模块收集从另一个模块导入的指令(如果导入模块的传递模块具有导出指令)或在当前模块中声明的指令

当 angular 编译属于模块 X 的模板时,它使用那些在 X.transitiveModule.directives.[= 中收集的指令44=]

compiledTemplate = new CompiledTemplate(
    false, compMeta.type, compMeta, ngModule, ngModule.transitiveModule.directives);

https://github.com/angular/angular/blob/4.2.x/packages/compiler/src/jit/compiler.ts#L250-L251

按照上图这样走

  • YComponent 不能在其模板中使用 ZComponent 因为 Transitive module Ydirectives 数组不包含 ZComponent 因为YModule 尚未导入 ZModule,其传递模块包含 exportedDirectives 数组中的 ZComponent

  • XComponent 模板中我们可以使用 ZComponent 因为 Transitive module X 有包含 ZComponent 的指令数组因为 XModule 导入模块 (YModule) 导出模块 (ZModule) 导出指令 ZComponent

  • AppComponent 模板中我们不能使用 XComponent 因为 AppModule 导入 XModuleXModule 不导出 XComponent.

另见

您必须 export 从您的 NgModule:

@NgModule({
  declarations: [TaskCardComponent],
  exports: [TaskCardComponent],
  imports: [MdCardModule],
  providers: []
})
export class TaskModule{}

无论您想从另一个模块使用什么,只需将其放入 导出数组。 像这样-

 @NgModule({
  declarations: [TaskCardComponent],
  exports: [TaskCardComponent],
  imports: [MdCardModule]
})

请注意,为了创建所谓的 "feature module",您需要在其中导入 CommonModule。因此,您的模块初始化代码将如下所示:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { TaskCardComponent } from './task-card/task-card.component';
import { MdCardModule } from '@angular2-material/card';

@NgModule({
  imports: [
    CommonModule,
    MdCardModule 
  ],
  declarations: [
    TaskCardComponent
  ],
  exports: [
    TaskCardComponent
  ]
})
export class TaskModule { }

此处提供更多信息:https://angular.io/guide/ngmodule#create-the-feature-module

解决了如何在其他模块中使用模块中声明的组件的问题。

基于 Royi Namir 的解释(非常感谢)。 在使用延迟加载时,缺少在任何其他模块中重用模块中声明的组件的部分。

1st:导出包含它的模块中的组件:

@NgModule({
  declarations: [TaskCardComponent],
  imports: [MdCardModule],
  exports: [TaskCardComponent] <== this line
})
export class TaskModule{}

第二:在你想使用TaskCardComponent的模块中:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MdCardModule } from '@angular2-material/card';

@NgModule({
  imports: [
   CommonModule,
   MdCardModule
   ],
  providers: [],
  exports:[ MdCardModule ] <== this line
})
export class TaskModule{}

像这样,第二个模块导入第一个模块,第一个模块导入和导出组件。

当我们导入第二个模块中的模块时,我们需要再次导出它。现在我们可以在第二个模块中使用第一个组件了。

一个伟大而伟大的方法是从 NgModuleFactory 加载模块,您可以通过调用此方法将模块加载到另一个模块中:

constructor(private loader: NgModuleFactoryLoader, private injector: Injector) {}

loadModule(path: string) {
    this.loader.load(path).then((moduleFactory: NgModuleFactory<any>) => {
        const entryComponent = (<any>moduleFactory.moduleType).entry;
        const moduleRef = moduleFactory.create(this.injector);
        const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
        this.lazyOutlet.createComponent(compFactory);
    });
}

我从 here (archived) 那里得到了这个。

(Angular 2 - Angular 7)

组件只能在单个模块中声明。 为了使用来自另一个模块的组件,你需要做两个简单的任务:

  1. 导出其他模块中的组件
  2. 将其他模块导入当前模块

第一个模块:

有一个组件(我们称它为:"ImportantCopmonent"),我们想在第二个模块的页面中重复使用。

@NgModule({
declarations: [
    FirstPage,
    ImportantCopmonent // <-- Enable using the component html tag in current module
],
imports: [
  IonicPageModule.forChild(NotImportantPage),
  TranslateModule.forChild(),
],
exports: [
    FirstPage,
    ImportantCopmonent // <--- Enable using the component in other modules
  ]
})
export class FirstPageModule { }

第二个模块:

通过导入 FirstPageModule

重用 "ImportantCopmonent"
@NgModule({
declarations: [
    SecondPage,
    Example2ndComponent,
    Example3rdComponent
],
imports: [
  IonicPageModule.forChild(SecondPage),
  TranslateModule.forChild(),
  FirstPageModule // <--- this Imports the source module, with its exports
], 
exports: [
    SecondPage,
]
})
export class SecondPageModule { }