menu

Questions & Answers

How to load different modules based on the url with angular?

I am trying to create an angular application, with two modules. One for the user part and one for the admin part.

I would like to load the module only if needed. For example if the requested url is /my-account it would load the user module. But if it's something that starts with /admin it should load the admin module.

After that i don't know if it's possible but each module should load his own routing (like app-routing).

For now i am just trying to change the bootstraped component based on the url.

I tried this solution: https://stackoverflow.com/a/53014303/10270107 But for me it doesn't work i have an error, and like the comment said everything is still loaded.

In my code i have two modules, one named PublicModule and AdminModule. Each modules have a simple component that only show a text "Public" and "Admin". Both component use the same selector <app-root>

Here is my AdminModule:

@NgModule({
  imports: [],
  declarations: [AdminRootComponent],
  exports: [AdminRootComponent],
  providers: [],
  entryComponents: [],
})
export class AdminModule {}

Here is my PublicModule:

@NgModule({
  imports: [],
  declarations: [PublicRootComponent],
  exports: [PublicRootComponent],
  providers: [],
  entryComponents: [],
})
export class PublicModule {}

Then that's inside my app.module.ts that I want to dynamically load the bootstrap component. For now I'm only able to switch components by uncommenting the commented line in the bootstrap and commenting the other one.

@NgModule({
  imports: [BrowserModule, FormsModule, PublicModule, AdminModule],
  declarations: [],
  bootstrap: [
    PublicRootComponent,
    //AdminRootComponent
  ],
})
export class AppModule {}

Here is my two components, first public-root.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './public-root.component.html',
})
export class PublicRootComponent {
  public constructor() {}
}

Then admin-root.component

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

@Component({
  selector: 'app-root',
  templateUrl: './admin-root.component.html',
})
export class AdminRootComponent {
  public constructor() {}
}

In the template I only have a simple text Public or Admin, depending on which component it is.

Comments:
2023-01-25 09:42:02
Sounds like you are trying to lazely load features depending on their route. angular.io/guide/lazy-loading-ngmodules could help you out
2023-01-25 09:42:02
Yes it's something like that, i didn't know that it existed. But then i still have an other point that i can't figure out: Since i have two modules, each module should have his routing. So is it possible to add a routing (<router-outlet></router-outlet>) inside a route ?
2023-01-25 09:42:03
Please ensure your code is included in the question – external links will change or be removed, rendering the question and its answers useless.
2023-01-25 09:42:03
^ Please do not link to external sources like pastebin or others. The reason is that when a link gets obsolete, the question is no longer useful to future readers. We are trying to build a lasting repository of useful question/answer pairs here. Please read can I just paste a link?
2023-01-25 09:42:03
Ok, i will edit my post is it ok if i do both, paste the code here and also link to the stackblitz ? Or should i juste put the code and delete my link ?
2023-01-25 09:42:03
I think it is ok to leave the link as a further reference, but only once you add your "essential" code to reproduce your issue. Please don't paste the whole project, but only the lines which cause the problem! Also keep in mind, there are a lot of users who don't like to, or simply don't click on external links
2023-01-25 09:42:03
I've edited the post, is it good like that or should i change other things ?
Answers(2) :

You can Create two angular libraries and build them as umd.js files Use Angular @angular/compiler to compile at run time. This works but needs research. Deprecated in V13 https://angular.io/api/core/Compiler

This is call LazyLoading: in the app.module you need to load the module according to route like this:

imports: [
  RouterModule.forRoot([
    {
      path: 'public',
      loadChildren: () => import('./public/public.module').then((m) => m.PublicModule),
    },
    {
      path: 'admin',
      loadChildren: () => import('./admin/admin.module').then((m) => m.AdminModule),
    },
  ]),
],

That will load the modules base on route

and inside the child modules you manage the route like this:

RouterModule.forChild([
  {
    path: 'fff',
    component: YourComponent,
  },
]),

Basically the different is that - in the parent module you need to use forRoot and in child modules you need to use forChild

Comments:
2023-01-25 09:42:03
Everything you said works fine, but now i still have one goal. I want to keep some html for each module. For exemple a navbar, it's not the same in the admin part or in the public part. I don't know if it's possible to use a <router-outlet></router-outlet> inside a child route, i can't find a way. Should i open an other question for that specific part ?
2023-01-25 09:42:03
you need to add some component for empty route inside child module like this: RouterModule.forChild([{path: '', component: HomeComponent}]), and inside HomeComponent you can put <router-outlet>
2023-01-25 09:42:03
Ok, and then how do i define which component should be in my <router-outlet> (the one inside my HomeComponent and not the one at the application root ?
2023-01-25 09:42:03
the one you declare inside forChild() are belong to the child module and they will load in the router-outlet in the HomeComponent ( also this components are part of the child module declarations array)