Search code examples
angularangular-ui-router

Question regarding multi router in angular11


I have a question here, I don't know have I follow the best practice of the angular even it is works now:

here is the structure of this nested component: pages

enter image description here

and here is my app-routing.module.ts file:

const routes: Routes = [
  { path: 'register', component: RegisterComponent },
  { path: 'home', component: HomeComponent },
  { path: 'login', component: LoginComponent },
  { path: 'welcome', component: WelcomeComponent, canActivate: [AuthGuard] },
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [AuthGuard],
    children: [{ path: 'team', component: TeamComponent }],
  },

  { path: '', redirectTo: 'home', pathMatch: 'full' },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

So, team component is the sub component of Admin component, there is a navigation bar in Admin component and it will render the team component inside.

Code for Admin component:

<app-nav-admin></app-nav-admin>

<router-outlet></router-outlet>

Code for navigation bar href to team component HTML:

   <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link" href="admin/team">Team management</a>
        </li>
        <li class="nav-item">
          <a class="nav-link">Link</a>
        </li>
      </ul>
    </div>

and result after click on team link: enter image description here

as you can see in href value, I assigned ""admin/team"" to go to team component and it really works, but is this is the best practice?

Thanks guys!


Solution

  • You're getting there almost. However, now if on one page you need the FormsModule because you want to use the NgModelDirective in your template, you will be loading the FormsModule for each page in the AppModule, even when you don't need it. Best practice is to implement route-level code-splitting, eg. use one module per page.

    You can use the following command to generate pages:

    ng g module register --module account --route account
    

    This will generate both a module and component that allows you to separate your dependencies. Full example:

    cd app
    ng g module pages --module app --route /
    cd pages
    ng g module account --module pages --route account
    cd account
    ng g module register --module account --route register
    ng g module login --module account --route login
    ng g module profile --module account --route profile
    

    Make sure that

    • the PagesModule is not imported in the AppModule
    • the AccountModule is not imported in the PagesModule
    • the RegisterModule, LoginModule, and ProfileModule are not imported in the AccountModule

    It also allows you to have a shared html banner or snippet whenever you're on any page related to, say account settings. In your case this would be in admin.componrnt.html:

    <app-nav-admin></app-nav-admin>
    <router-outlet></router-outlet>
    

    You will notice that the size of your main.xxxxxx.js (main bundle) decreases drastically), so your app will load faster. However when navigating, the other modules needed for the other page aren't loaded yet, so you will experience a delay. To resolve this, you can use the preloadingstrategy: PreloadAllModules in the options of your RouterModule.forRoot() call (app-routing.module.ts)

    Also note that the resulting AccountRoutingModule has the following routes:

    const routes: Routes = [
      { path: 'login', loadChildren: () => import('./login/login.module').then(m => m.LoginModule) },
      { path: 'register', loadChildren: () => import('./register/register.module').then(m => m.RegisterModule) },
      { path: 'profile', loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule) },
    ];
    

    The import('') instruction decouples your modules, while still allowing strong-type-checking. So the modules do not need to be imported in the AccountModule.

    As a sidenote, you can you Lighthouse, which is built-in in Chrome, to evaluate your website. It will detect that you have an angular app, and one of the suggestions will be the use of route-level code-splitting. Since Lighthouse detects that the entire javascript application is loaded at once, including modules it doesn't need at that time. To use Lighthouse, in Chrome simply press F12 to open developer tools, and there will be a tab Lighthouse.