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

Posted

技术标签:

【中文标题】使用来自另一个模块的组件【英文标题】:Use component from another module 【发布时间】:2017-01-28 19:58:26 【问题描述】:

我有使用 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

【问题讨论】:

【参考方案1】:

一个非常棒的方法是从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) 得到这个。

【讨论】:

NgModuleFactoryLoader 现在已被弃用,那么它最好的替代方法是什么?【参考方案2】:

这里的主要规则是:

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

所以,尝试导出它:

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

我应该导出什么?

导出其他模块中的组件应该是可声明的类 能够在他们的模板中引用。这些是你的公开课。 如果你不导出一个类,它会保持私有,只对其他人可见 在此模块中声明的组件。

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

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

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

当 Angular 编译属于模块 X 的模板时,它会使用那些在 X.transitiveModule.directives 中收集的指令。

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,其传递模块包含ZComponent exportedDirectives 数组。

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

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

另见

why lazy loaded module has to import commonModule? Angular 2

Angular Module FAQs

What is the difference between declarations, providers, and import in NgModule?

【讨论】:

如何在导入模块的路由定义中使用这个“TaskCardComponent”? 多么棒的答案。你创建了图纸吗?如果是这样,我无语了。不是每个人都在他们的答案中付出了这样的努力。谢谢 @Royi 是的,这是我的照片 :) 它基于来自github.com/angular/angular/blob/master/packages/compiler/src/…的源代码 @yuruzi,没有引用***.com/questions/47246638/…plnkr.co/edit/DnnjFBa3HLzFKNIdE4q5?p=preview,我无法直接传递dom节点 @yurzui ...我不明白 YComponent 如何导出 ZModule,因为我将其视为一个单独的文件(y.module.ts)并且它没有任何导入,因此导出其他模块(即 z.module.ts)[如果它的基本问题请告诉我]【参考方案3】:

(角度 2 - 角度 7)

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

    导出其他模块中的组件 将其他模块导入到当前模块中

第一个模块:

有一个组件(我们称之为“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  

【讨论】:

虽然不像原来那样冗长,但这是您需要做的两件事,而导出组件是最常被遗忘的一件事。这是一个简单的答案。【参考方案4】:

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

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

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

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

2nd:在要使用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

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

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

【讨论】:

【参考方案5】:

请注意,为了创建所谓的“功能模块”,您需要在其中导入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

【讨论】:

【参考方案6】:

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

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

【讨论】:

【参考方案7】:

你必须从你的NgModuleexport它:

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

【讨论】:

这个工作,直到 TaskModule 被导入 AppModule。当 TaskModule 被延迟加载时它会失败。

以上是关于使用来自另一个模块的组件的主要内容,如果未能解决你的问题,请参考以下文章

在子模块中使用来自导入模块的组件

如何在另一个组件中使用来自组件的表单

如何在angularjs4中触发另一个组件的点击事件功能

如何在Angular 11中显示来自另一个组件的模态组件

在另一个 bean 中使用来自一个 bean(组件)的方法是不是正确?

Java swing 添加来自另一个类的组件