yourfriendzak yourfriendzak - 3 months ago 79
TypeScript Question

Feature module not exporting component

My simple app has a root module named AppModule and a feature module named HomeModule. I'm trying to create a route for a component named HomeComponent (which is part of HomeModule) but all I get is

Module "HomeModule" has no exported member 'HomeComponent'


app.routing.ts

import { Routes, RouterModule } from '@angular/router'
import { HomeComponent } from './Home/home.module.ts' // HomeComponent not found

const appRoutes: Routes = [
{ path: '', component: HomeComponent }
];

export const appRoutingProviders: any[] = [

];

export const routing = RouterModule.forRoot(appRoutes);


home.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { HomeComponent } from './home.component.ts';

@NgModule({
imports: [ BrowserModule ],
declarations: [ HomeComponent ],
exports: [ HomeComponent ]
})

export class HomeModule { }


home.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'home',
template: '<h1>Hello World</h1>'
})

export class HomeComponent { }


Why is HomeModule not exporting its component?

Answer

Ref1:http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html Ref2:https://angular.io/docs/ts/latest/guide/ngmodule.html#!#imports

Issue 1: NgModel Import/Export

import { HomeComponent } from './Home/home.module.ts' // HomeComponent not found

home.module.ts exports HomeModule, not HomeComponent.

@NgModule exports make Angular2 features of those export components available to the importing module. features can be template directives, selector, injectable service, etc.

Home component feature is its selector. So importing HomeModule into app.module will make HomeComponent selector home available to any app.module's component.

To have HomeModule export HomeComponent explictly, index.js and index.d.ts are needed. (Inspired by Fabio Antunes answer)

Use selector home

To use this, exports: [ HomeComponent ] is required in home.module.ts.

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

import { HomeModule } from './Home/home.module';

import { routing } from './app.routing';

@NgModule({
    imports: [
        BrowserModule,
        HomeModule,
        routing],
    declarations: [
        AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts using selector home

import {Component} from '@angular/core';

@Component({
    selector: 'app-component',
    template: `
        <h1>{{title}}</h1>
        <home></home>`
})
export class AppComponent {
    title = 'APP';
}

Use HomeComponent

To use HomeComponent directly, we need to add index.js and index.d.ts into ./Home

./Home/index.js

exports.HomeModule = require('./home.module').HomeModule;
exports.HomeComponent = require('./home.component').HomeComponent;

./Home/index.d.ts

exports * './home.module';
exports * from './home.component';

Then import Home Module like npm package

app.routing.ts

// We are importing the module directory, not ./Home/home.module.ts
import { HomeComponent } from './Home';

import { Routes, RouterModule } from '@angular/router'

const appRoutes: Routes = [
  { path: '', component: HomeComponent }
];

export const appRoutingProviders: any[] = [

];

export const routing = RouterModule.forRoot(appRoutes);

Issue 2: Routing (to child module)

To route to a module, the child module need to have its own router setup.

Use loadChildren in parent routing(app.routing.ts).

Use RouterModule.forChild in child routing(home.routing.ts).

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

import { HomeModule } from './Home/home.module';

import { routing } from './app.routing';

@NgModule({
    imports: [
        BrowserModule,
        HomeModule,
        routing],
    declarations: [
        AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import {Component} from '@angular/core';

@Component({
    selector: 'app-component',
    template: `
        <h1>{{title}}</h1>
        <nav>
      <a routerLink="/home" routerLinkActive="active">Home</a>
    </nav>
    <router-outlet></router-outlet>`
})
export class AppComponent {
    title = 'APP';
}

app.routing.ts

import { Routes, RouterModule } from '@angular/router';

const appRoutes: Routes = [
    {
        path: '',
        redirectTo: '/home',
        pathMatch: 'full'
    },
    {
        path: 'home',
        loadChildren: './Home/home.module'
    }
];

export const appRoutingProviders: any[] = [

];

export const routing = RouterModule.forRoot(appRoutes);

Home/home.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { HomeComponent }  from './home.component';

import { routing } from './home.routing';

@NgModule({
  imports: [
    BrowserModule,
    routing],
  declarations: [
    HomeComponent]
})

export class HomeModule { }

Home/home.routing.ts

import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './home.component';

const homeRoutes: Routes = [
    {
        path: '',
        redirectTo: '/home',
        pathMatch: 'full'
    },
    {
        path: 'home',
        component: HomeComponent
    }
];

export const appRoutingProviders: any[] = [

];

export const routing = RouterModule.forChild(homeRoutes);