241

I have Angular 2.0.0 app generated with angular-cli.

When I create a component and add it to AppModule's declarations array it's all good, it works.

I decided to separate the components, so I created a TaskModule and a component TaskCard. Now I want to use the TaskCard in one of the components of the AppModule (the Board component).

AppModule:

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 { }

TaskModule:

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{}

The whole project is available on https://github.com/evgdim/angular2 (kanban-board folder)

What am I missing? What do I have to do to use TaskCardComponent in BoardComponent?

Alexander Abakumov
  • 10,817
  • 10
  • 71
  • 111
Evgeni Dimitrov
  • 19,437
  • 29
  • 105
  • 137

7 Answers7

450

The main rule here is that:

The selectors which are applicable during compilation of a component template are determined by the module that declares that component, and the transitive closure of the exports of that module's imports.

So, try to export it:

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

What should I export?

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.

The minute you create a new module, lazy or not, any new module and you declare anything into it, that new module has a clean state(as Ward Bell said in https://devchat.tv/adv-in-angular/119-aia-avoiding-common-pitfalls-in-angular2)

Angular creates transitive module for each of @NgModules.

This module collects directives that either imported from another module(if transitive module of imported module has exported directives) or declared in current module.

When angular compiles template that belongs to module X it is used those directives that had been collected in 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

enter image description here

This way according to the picture above

  • YComponent can't use ZComponent in its template because directives array of Transitive module Y doesn't contain ZComponent because YModule has not imported ZModule whose transitive module contains ZComponent in exportedDirectives array.

  • Within XComponent template we can use ZComponent because Transitive module X has directives array that contains ZComponent because XModule imports module (YModule) that exports module (ZModule) that exports directive ZComponent

  • Within AppComponent template we can't use XComponent because AppModule imports XModule but XModule doesn't exports XComponent.

See also

yurzui
  • 171,085
  • 24
  • 365
  • 354
  • 14
    How do I use this "TaskCardComponent" in a route definition in the Importing module? – jackOfAll Dec 07 '16 at 07:52
  • 26
    What a great answer. Did you create the drawing? If so, I'm speechless. Not everyone put such effort in their answers. Thank you – Royi Namir Jun 19 '17 at 20:13
  • 4
    @Royi Yes, this is my picture :) It's based on source code from https://github.com/angular/angular/blob/master/packages/compiler/src/metadata_resolver.ts#L424 – yurzui Jun 19 '17 at 20:17
  • @yuruzi, i cannot pass the dom node directly without the reference https://stackoverflow.com/questions/47246638/calling-a-function-of-a-directive-from-angular-component-doesnt-work/47246984?noredirect=1#comment81445076_47246984 https://plnkr.co/edit/DnnjFBa3HLzFKNIdE4q5?p=preview – Karty Nov 12 '17 at 10:05
  • @yurzui ... I don't understand how can YComponent export ZModule, since I am seeing that as a separate file (y.module.ts) and it doesn't have any import so as to export other module (which is z.module.ts) [bear me if its basic question] – OmGanesh Sep 27 '19 at 14:22
  • Hi @yurzui I have this confusion, lets say I have a module A which exports 10 components. If I import this module A into another module B(which needs just one component from module A) 1. Will it import all the classes exported from module A? 2. If Yes how can I avoid it. 3. Does it depend of what I import from module A will be added to module B 4. Will it affect memory or performance to load entire module with 10 components thoe u need 1. I was trying to find the answers to this but could not find a suitable answer. – Praveen Pandey Mar 03 '20 at 06:23
  • one of the best answers i have ever seen in SO...... – AhammadaliPK Aug 07 '20 at 03:24
  • The best answer ever, he asked for a finger he gave him a hand xD, thanks bro – Amor.o Dec 31 '20 at 15:09
64

(Angular 2 - Angular 7)

Component can be declared in a single module only. In order to use a component from another module, you need to do two simple tasks:

  1. Export the component in the other module
  2. Import the other module, into the current module

1st Module:

Have a component (lets call it: "ImportantCopmonent"), we want to re-use in the 2nd Module's page.

@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 { }

2nd Module:

Reuses the "ImportantCopmonent", by importing the FirstPageModule

@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 { }
Saksham
  • 8,110
  • 6
  • 35
  • 63
Eyal c
  • 1,013
  • 8
  • 7
42

You have to export it from your NgModule:

@NgModule({
  declarations: [TaskCardComponent],
  exports: [TaskCardComponent],
  imports: [MdCardModule],
  providers: []
})
export class TaskModule{}
slaesh
  • 14,973
  • 6
  • 44
  • 48
  • 2
    This Works, till TaskModule is imported in AppModule. It fails when TaskModule is lazyloaded. – Arun Jan 06 '17 at 11:30
2

Note that in order to create a so called "feature module", you need to import CommonModule inside it. So, your module initialization code will look like this:

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 { }

More information available here: https://angular.io/guide/ngmodule#create-the-feature-module

nostop
  • 194
  • 1
  • 5
0

Whatever you want to use from another module, just put it in the export array. Like this-

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

One big and great approach is to load the module from a NgModuleFactory, you can load a module inside another module by calling this:

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);
    });
}

I got this from here.

Gaspar
  • 1,177
  • 10
  • 19
-3

SOLVED HOW TO USE A COMPONENT DECLARED IN A MODULE IN OTHER MODULE.

Based on Royi Namir explanation (Thank you so much). There is a missing part to reuse a component declared in a Module in any other module while lazy loading is used.

1st: Export the component in the module which contains it:

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

2nd: In the module where you want to use 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{}

Like this the second module imports the first module which imports and exports the component.

When we import the module in the second module we need to export it again. Now we can use the first component in the second module.

christianAV
  • 85
  • 1
  • 3