Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 960
zakdances Avatar asked Aug 10 '16 18:08

zakdances


3 Answers

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);
like image 175
John Siu Avatar answered Sep 23 '22 16:09

John Siu


Feature modules should import CommonModule instead of BrowserModule

like image 21
Yakov Fain Avatar answered Sep 24 '22 16:09

Yakov Fain


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'.

like image 44
Husein Roncevic Avatar answered Sep 25 '22 16:09

Husein Roncevic