1

I am writing an Angular 8 app and I am trying to lazy load some modules. However, when the page loads, I get this error:

Error: Component ProfileComponent is not part of any NgModule or the module has not been imported into your module.

Specifically, I wish to load a module when a route is hit and a component loads. The problem is that the component is part of the module.

Here is code for the sub module, where the component is defined:

@NgModule({
  imports: [],
  declarations: [
    ...
    ProfileComponent
  ],
  exports: [
    ...
    ProfileComponent
  ]
 })
 export class ProfileModule { }

Here is the route definition in the parent module trying to dynamically load the sub-module:

const routes: Routes = [
  {
   path: 'projects/profile/:id', component: ProfileComponent,  
     loadChildren: () => {
       return import('./profile/profile.module').then(m => m.ProfileModule);
     },
     children: [
       { path: 'list/:id', component: ListComponent, outlet: 'sidebar' },
       { path: 'risk/:id', component: RiskComponent, outlet: 'sidebar' },
       ...
   ]
 }

Is there a way to load the Component and Module on navigate? I tried moving the offending ProfileComponent into the parent module, but it expects all of its sub components to exist when I navigate to the page (which is counter to the lazyloading). I can create a landing page that uses no sub components where I can click to redirect to my route that dynamically loads the sub module, but I would rather not add another layer of clicking to the app.

terahertz
  • 2,915
  • 1
  • 21
  • 33
afriedman111
  • 1,925
  • 4
  • 25
  • 42
  • Your parent module shouldn't list the children directly, it should just use the `loadchildren`. And then give your submodule its own routing file to forward the request to its component. ; After all, lazy loading is only lazy if your parent has no references to the content of the submodule. And you also don't need to export the component. – bvdb Jul 28 '19 at 23:22

2 Answers2

4

why just not use in parent module

const routes: Routes [{path:'projects/profile/:id', loadchildren: './profile/profile.module#ProfileModule']

and then in subModule

const subRoutes: Routes .....
@NgModule({
imports: [RouterModule.forChild(subRoutes)]
exports: [RouterModule]

for more info you can check Angular Routing & Navigation => Milestone 3: Heroes feature

Hope this helps ;-)

Community
  • 1
  • 1
jspassov
  • 791
  • 7
  • 11
  • I now get the error: Error: Cannot match any routes. URL Segment: 'projects/profile/18'. I searched around and found that there is a problem with using a named router outlet with lazy loading. The recommendation is to use non-empty paths with top level routes. I tried different permutations of this, but couldn't get rid of the error. Could you elaborate what the routes in the submodule would look like with the route parameter and the named router outlet? – afriedman111 Jul 29 '19 at 00:19
1

Structure of your app:

├── parent.module.ts/
│   ├── profile.module.ts/
│       └──profile.component.ts/
  • If profile module hasn't been loaded yet, profile component doesn't exist in parent module's context, hence you got the error, "the module has not been imported into your module".

If I didn't misunderstand your question, you should declare another set of routes in ProfileModule like this:

ProfileModule (Not Parent Module)

const routes: Routes = [
   { path: '', component: ProfileComponent }, // /projects/profile/1
   { path: 'list/:id', component: ListComponent, outlet: 'sidebar' }, // /projects/profile/1/list/15 
   { path: 'risk/:id', component: RiskComponent, outlet: 'sidebar' } ///projects/profile/1/risk/20
]

//and then import it into your parent module RouterModule

@NgModule({
  declarations: [ProfileComponent],
  imports: [ RouteModule.forChild(routes) ],
  exports: [ RouterModule ]
})

ParentModule - remove ProfileComponent

const routes: Routes = [
  {
   path: 'projects/profile/:id', loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule)
  }
]

It is correct to use the import keyword for lazy loading in Angular 8 since the string syntax has been deprecated but you can keep it less verbose by removing the return keyword.

terahertz
  • 2,915
  • 1
  • 21
  • 33
  • There is another problem. The child components for the child routes that you defined in the parent routing module are only defined in the sub module. They aren’t available in the parent. – afriedman111 Jul 29 '19 at 12:16
  • In that case you can shift them into your sub module as direct routes (is it profile module that you're referring to?). Also, it depends hugely on how you want the route to look like. *I have edited my answer – terahertz Jul 29 '19 at 13:11
  • I'm getting an error saying the route cannot be found. I think this is a complicated problem because I am using both route params and a named router outlet. I found [this](https://stackoverflow.com/a/46921614/6569899) and [this](https://stackoverflow.com/a/47487220/6569899) but neither helped. I can get the module loading if I take out the route param and use an empty string for the top level route in my submodule, but the page doesn't load – afriedman111 Jul 29 '19 at 22:20
  • Is this the behaviour you are looking for? https://stackblitz.com/edit/angular-zbgnpq I have created this stackblitz, and it seems to work fine. I am able to access `/profile/2/risk/1` or `/profile/2/list/1`. Have a look at it and try to match it to your context? – terahertz Aug 01 '19 at 02:28
  • Thanks for the example. I wasn't able to get the subroutes to load though. I did find an answer that is located [here](https://stackoverflow.com/a/57291595/6569899). – afriedman111 Aug 01 '19 at 17:14