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?
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
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)
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';
}
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);
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);
Feature modules should import CommonModule instead of BrowserModule
When setting up a route where your app.route.ts
will load your HomeModule using loadChildren
there are two things you must do. Either:
export default class HomeModule() {} // note *default*
or in your app.route.ts
you need to add #HomeModule
:
import { Routes, RouterModule } from '@angular/router';
const appRoutes: Routes = [
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
},
{
path: 'home',
loadChildren: './Home/home.module#HomeModule' <-- or like this
}
];
export const appRoutingProviders: any[] = [
];
export const routing = RouterModule.forRoot(appRoutes);
If you plan to add additional routes to the home.route.ts it might be a good idea to define children
property like:
import { Routes, RouterModule } from '@angular/router';
const homeRoutes: Routes = [
path: "",
component: HomeComponent,
children: [
{
path: "",
component: HomeComponent
},
{
path: ":id",
component: HomeDetailsComponent"
}
]
]
What you have to remember in the above case is that your main RouterOutlet
in your app.component.ts (if it is called like that), is not going to serve the route such as http://some_url/Home/1
in order to load HomeDetailsComponent.
The thing is that the route served by HomeDetailsComponent
is a child route of HomeComponent
and as such HomeComponent's template
or templateUrl
must have it's own <router-outlet></router-outlet>
defined, othwerise you will get an error message Cannot find primary outlet to load 'HomeDetailsComponent'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With