I am currently using Angular 2 - RC5 with the router 3.0.0 RC1. This seems to be a pretty common error, but I can't find any solution that works. My component structure includes a "BasicContentComponent" which includes the main menu and the header and an aux outlet for the content of the child route. The "BasicContentComponent" comes from a shared module and the child routes component from specific module of that child route.
My route configuration looks like this
export const routeConfig = [
{
path: 'home',
component: BasicContentComponent,
children: [
{
path: '',
component: HomeContainer,
//canActivate: [IsAuthenticatedGuard],
outlet: 'content', // REMOVE THIS LINE
//resolve: {
// homeState: HomeResolver
//}
}
]
}
];
If I remove the "children" definition I am able to load "/home" but with this configuration I get the error.
Following are the module configurations, since the problem may also lie there.
app.module.ts
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
RouterModule.forRoot(routeConfig), //see above
SharedModule.forRoot(),
HomeModule
],
bootstrap: [AppComponent]
})
export class AppModule {}
shared.module.ts
import { Store, StoreModule } from '#ngrx/store';
#NgModule({
imports: [
RouterModule,
CommonModule,
...
StoreModule.provideStore(reducers),
],
declarations: [
BasicContentComponent,
...
],
exports: [BasicContentComponent, ...],
})
export class SharedModule {
static forRoot() : ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [
MdIconRegistry,
...
IsAuthenticatedGuard,
...
HomeResolver
]
}
}
}
home.module.ts
#NgModule({
imports: [CommonModule, SharedModule],
declarations: [
HomeContainer,
HomeComponent
],
exports: [HomeContainer]
})
export class HomeModule { }
I get the following error
browser_adapter.js:84 EXCEPTION: Error: Uncaught (in promise): Error:
Cannot match any routes: 'home'
Any idea what the problem could be? Is it a route config or a modules issue? thanks
Edit
I forgot the templates:
app.component.html
<div>
<router-outlet></router-outlet>
</div>
basic-content.component.html
<md-sidenav-layout fullscreen>
<md-sidenav mode="side" align="start" [opened]="isOpened$ | async" color="warn">
<mainnav-container></mainnav-container>
</md-sidenav>
<page-header-container></page-header-container>
<div class="app-content">
<router-outlet name="content"></router-outlet> // REMOVE NAME
</div>
</md-sidenav-layout>
I got help on Gitter. If I remove the "name" attribute of the router-outlet and also remove it from the routerConfig everything works as intended. I don't fully understand why I have to remove it and how exactly the router finds the correct outlet - it makes kinda sense since the outlets are nested - but I will udpate my answer at a later point when the documentation for named outlets is more complete.
Thanks to #DzmitryShylovich on Gitter.
Related
i have this psuedo code structure in my angular project.
wrapper.module
Wrapper.module.ts
#NgModule({
declaration: [WrapperComponent.ts]
imports: [
WrapperRouting.module
]
})
wrapper-routing.module.ts
WrapperRouting.module
routes = [
{
path: '',
component: wrapper.component.ts ,
children: [
{ path: '', loadChildren: Component1.module.ts},
{ path: '2', loadChildren: Component2.module.ts},
]
}
];
component1.module.ts
#NgModule({
declaration: [Component1Component, ShowTableComponent]
imports: [
Component1Routing.module
]
})
component1.component.ts
<show-table></show-table>
component2.module.ts
#NgModule({
declaration: [Component2Component, ShowTableComponent]
imports: [
Component2Routing.module
]
})
component2.component.ts
<show-table></show-table>
Im trying first to declar the ShowComponent in Component1.module.ts and Component2.module.ts however I got an error that ShowComponent is declared in two module.
Then, tried to put in the the parent module which is Wrapper.module.ts the error would be: ShowComponent is an Angular component, then verify that it is part of this module.
Can someone help me, much appreciated!
Can you please clarify how you are defining the parent-child relationship between all of these modules. Because there is no specific way to depict a parent-child relationship between modules in angular.
If you want to use the
<show-table></show-table>
in component1.module and component2.module, you have to add the wrapper.module in the imports array of both modules i.e. component1.module and component2.module and add the ShowComponent in the exports array of Wrapper.module.
After which your respective code will become as follows
Component1.module.ts
#NgModule({
declarations: [
Component1
],
imports: [
WrapperModule
]
})
export class Component1Module { }
Component2.module.ts
#NgModule({
declarations: [
Component2
],
imports: [
WrapperModule
]
})
export class Component2Module { }
wrapper.module.ts
#NgModule({
declarations: [
ShowComponent
],
exports: [
ShowComponent
]
})
export class WrapperModule { }
P.S. This method is used when you have to use a component from a different module in the HTML of a component. If you are using <router-outlet></router-outlet> you don't have to worry about importing the modules to use a component. You can just specify the name of the component in the routes array.
Do let me know if my answer helped you!
I have a structure like this:
home - page
home2 - page
test-component - component
I need to be able to use the component(<app-test-component></app-test-component>) on both pages.
If I just use the tag:
ERROR Error: Uncaught (in promise): Error: Template parse errors:
'app-test-component' is not a known element:
If I just import (import {TestComponentComponent} from '../test-component/test-component.component') into home.module.ts and put it in the module import:
core.js:9110 ERROR Error: Uncaught (in promise): Error: Unexpected
directive 'TestComponentComponent' imported by the module
'HomePageModule'. Please add a #NgModule annotation.
A similar error if added to declarations.
Git.
How to import a component on both pages and use?
There are few changes that you should make:
You should not import component as I can see in the code.
Rearrange the project structure, and move reusable component such as TestComponent into a shared component. To give you an example, I'll give below example where I have created shared module names as TestModule
/app
/home
-home.component.ts
-home.module.ts
/test
-test.component.ts
-test.module.ts
-app.component.ts
-app.module.ts
app.module.ts
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HomeModule, RouterModule.forRoot([{ path: '', component: HomeComponent }])],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
test.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { TestComponent } from './test.component';
#NgModule({
declarations: [TestComponent],
exports: [TestComponent],
imports: [CommonModule],
})
export class TestModule {}
home.module.ts
#NgModule({
declarations: [HomeComponent],
exports: [HomeComponent],
imports: [
CommonModule,
TestModule
]
})
export class HomeModule { }
This set of project structure would certainly help you to reuse test.module features. Let me know if you need more code.
Declare TestComponentComponent only in home.module.
home.module.ts
#NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild([
{
path: '',
component: HomePage
}
])
],
declarations: [HomePage, TestComponentComponent]
})
export class HomePageModule {}
app.module.ts
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
I have a parent module where i'm lazy loading a child module
As you may see , i don't import my child module directly , but i'm loading it lazily under routing file :
Parent Module :
#NgModule({
imports: [
CommonModule,
ParentRoutingModule,
],
exports: [
ParentRoutingModule
],
declarations: [ParentComponent]
})
export class ParentModule { }
Parent Routing Module :
const parentRoutes: Routes = [
{path: '', component: ParentHomeComponent},
{
path: '',
loadChildren: () => ChildModule,
canLoad: [ChildModuleGuard]
},
];
#NgModule({
imports: [
CommonModule,
RouterModule.forChild(parentRoutes)
],
declarations: [],
exports: [
RouterModule
]
})
export class ParentRoutingModule { }
In my main ParentModule component ; the ParentHomeComponent i want to inject the view of my ChildHomeCOmponent , like this :
<p>
Parent-home works!
</p>
<app-Child-home></app-Child-home>
but this throws an error telling that the ChildHomeComponent isn't
part of the ParentModule (as i'm not importing it directly) ;
How to deal with that ??
I want that if the module is loaded , my child home component gets displayed under the parent home component
Suggestions ??
This is not how lazy loading works in Angular.
Non-lazy loaded modules cannot access components from lazy loaded modules.
I have a lazy load module which needs to expose providers, so I am using the forRoot convention and returning the following code:
#NgModule({
imports: [RouterModule.forChild([
{path: "", component: LazyComponent},
])],
declarations: [LazyComponent],
})
export class LazyModule {
static forRoot() {
return {
ngModule: LazyModule,
providers: [provider]
};
}
}
The problem is when I invoke the forRoot in my app module the lazy load does not work anymore. ( I don't see the separate chunk in my console )
#NgModule({
declarations: [
AppComponent,
HelloComponent
],
imports: [
BrowserModule,
AppRoutingModule,
LazyModule.forRoot() <======== this stops the lazy load module
],
bootstrap: [AppComponent]
})
export class AppModule {
}
From what I learned it should only make the providers singleton, why it does not work?
As of right now, it's not possible to execute a forRoot (or any other configuration static method of this sort) in a module that will load lazily. The problem here is that such a method returns a ModuleWithProviders while loadChildren requires a NgModuleFactory.
I faced a similar issue where I had to lazy load a module with some configurations. So, I came up with this temporary fix.
Lazy Module
#NgModule({
imports: [
RouterModule.forChild([
{path: "", component: LazyComponent},
])],
declarations: [LazyComponent],
})
export class LazyModule {
// considering the function only handle providers
static setDynamicProviders(provider?: any) {
if(LazyModule && LazyModule.__annotations__ && LazyModule.__annotations__[0]){
LazyModule.__annotations__[0].providers.push(provider);
}
return LazyModule;
}
}
Parent Module
const someService = {
provide: 'SOME_TOKEN',
useFactory: (dependecy1) => (//dome something with dependency1)
deps: [SOME_DEPENDENCY_TOKEN]
}
#NgModule({
imports: [
RouterModule.forRoot([
path: 'lazy',
loadChildren: ()=>(import('*your path to lazy module*').then(ref => ref.LazyModule.setDynamicProvider(someService)))
])
]
})
So, I am just modifying the annotations created by #NgModule Decorator. At this stage, Angular does not support lazy loading with static methods that return ModuleWithProviders.
When you import a LazyModule in your AppModule imports array it is not "lazy" anymore. A lazy module should only be referenced in a dedicated RoutingModule.
So if I understood you correctly you would like to share a Service between your LazyModules?
If so remove LazyModule from AppModule and create a SharedModule and move your Service you like to share inside the providers array in SharedModule. Import SharedModule in your AppModule with forRoot and import your SharedModule without forRoot in your LazyModules
Try below code when we define a module is Lazy RouterModule.forChild:
#NgModule({
imports: [RouterModule.forChild([
{path: "", component: LazyComponent},
])],
declarations: [LazyComponent],
})
export class LazyModule { }
But when we load in the parent module, try the below code:
#NgModule({
declarations: [
AppComponent,
HelloComponent
],
imports: [
BrowserModule,
AppRoutingModule,
RouterModule.forRoot([
{
path: '',
loadChildren: './layout/layout.module#LayoutModule',
canActivate: [AuthGuard]
}
]) <======== right way to load lazy module
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Note: FullPath is like './moduleFolder/lazy.module#LayoutModule'
LayoutModule is your exported Module Name
Please let me know
I have an Angular module that I'm loading from an NPM module. How do I load the routes from it? Here is a snippet from my app.module.ts file:
import { HelloWorldModule } from 'hello-world-app-npm/hello-world-app.umd.js'; // The module loaded from NPM
const routes = [
{ path: 'hw', loadChildren: () => HelloWorldModule },
{ path: '', component: AppComponent },
]
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HelloWorldModule,
FormsModule,
HttpModule,
RouterModule.forRoot(routes)
],
exports: [RouterModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Here is how I've define my hello world module:
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { HelloWorldComponent } from './hello-world.component';
export const routes = [{ path: '', component: HelloWorldComponent }]
#NgModule({
bootstrap: [HelloWorldComponent],
declarations: [
HelloWorldComponent
],
imports: [
RouterModule.forChild(routes)
]
})
export class HelloWorldModule {
}
When I go to "/hw" I get an error in chrome saying
Uncaught (in promise): RangeError: Maximum call stack size exceeded
What am I doing wrong? How do I fix this?
I suspect it could be because of two things.
HelloWorldModule should not be appear inside AppModule import.
bootstrap: [HelloWorldComponent] inside HelloWorldModule is unnecessary.