In this step-by-step tutorial you will learn how to create a multiview application using Angular 15, with custom ngModules
(core, feature and shared), lazy loading, primary and nested routes
Now we create the pages of the application. Each page is often associated to a specific URL, also knows as "route".
Our secondary goal is to split the code in several chunks by enabling "lazy loading" and optimizing the performance when the application starts.
For each route we create:
Here you can see the final result of this recipe:
So let's start creating the "Setting" Page.
This command generates the main (routed) component, its own "feature" module and a "routing" module.
Furthermore, it also adds a new path to the AppRoutingModule
file, named settings
:
ng g m features/settings --route settings --module app.module
It generates the following new folder:
The "Routed" module is the module that will be associated to a route "path" and lazy loaded:
settings.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SettingsRoutingModule } from './settings-routing.module';
import { SettingsComponent } from './settings.component';
@NgModule({
declarations: [
SettingsComponent
],
imports: [
CommonModule,
SettingsRoutingModule
]
})
export class SettingsModule { }
The "Routing Module" defines the default component to load when the route is visited:
settings-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SettingsComponent } from './settings.component';
const routes: Routes = [{ path: '', component: SettingsComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SettingsRoutingModule { }
SettingsComponent
is the component that will be loaded when the route is visited:
settings.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-settings',
template: `
<p>
settings works!
</p>
`,
styles: [
]
})
export class SettingsComponent { }
And now you can create other two routes, /home
and /users
:
ng g m features/home --route home --module app.module
ng g m features/users --route users --module app.module
The previous commands generate the following files:
I love this command because the app-routing.module.ts
is magically updated too, adding a new rule for each route / module and applying the "lazy loading".
app-routing.module
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: 'settings', loadChildren: () => import('./features/settings/settings.module').then(m => m.SettingsModule) },
{ path: 'home', loadChildren: () => import('./features/home/home.module').then(m => m.HomeModule) },
{ path: 'users', loadChildren: () => import('./features/users/users.module').then(m => m.UsersModule) }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
In fact you can now access each route through a specific url:
Now you need to create a fallback for users that:
http://localhost:4200
http://localhost:4200/anything
Use the wildcard **
Open app-routing.module
and add the **
redirect:
app-routing.module
const routes: Routes = [
{ path: 'settings', loadChildren: () => import('./features/settings/settings.module').then(m => m.SettingsModule) },
{ path: 'home', loadChildren: () => import('./features/home/home.module').then(m => m.HomeModule) },
{ path: 'users', loadChildren: () => import('./features/users/users.module').then(m => m.UsersModule) },
// NEW
{ path: '**', redirectTo: 'home' },
];
You can now test if the default route works by visiting the default url:
it should automatically redirect to /home
.
You can also try to use a wrong url, just like http://localhost:4200/anything, and you should be automatically redirected to the /home
again.
Update the navigation bar component to enable the navigation.
You can simply use routerLink
and routerLinkActive
directives included in RouterModule
:
routerLink
: simply navigates to a specified path without refreshing the applicationrouterLinkActive
: apply a custom CSS class to the element when the browser url matches the routerLink
pathAdd RouterModule
to core/core.module.ts
since we use its directives in the NavBar
component.
core.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router'; // <=== NEW
import { NavbarComponent } from './components/navbar.component';
@NgModule({
imports: [
CommonModule,
RouterModule // <=== NEW
],
declarations: [NavbarComponent],
exports: [NavbarComponent]
})
export class CoreModule { }
Open core/components/navbar.component.ts
and use routerLink
and routerLinkActive
.
You can just replace previous content copy-pasting the following:
navbar.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-navbar',
template: `
<nav class="navbar navbar-expand navbar-dark bg-dark text-white">
<a class="navbar-brand">LOGO</a>
<div class="navbar-collapse collapse">
<ul class="navbar-nav">
<li class="nav-item" routerLink="/home" >
<a class="nav-link" routerLinkActive="active">Home</a>
</li>
<li class="nav-item" routerLink="/settings">
<a class="nav-link" routerLinkActive="active">Settings</a>
</li>
<li class="nav-item" routerLink="/users">
<a class="nav-link" routerLinkActive="active">Users</a>
</li>
</ul>
</div>
</nav>
`
})
export class NavbarComponent { }
Now you should be able to navigate the application by using the navigation bar:
Now open the Network tab of your (Chrome) dev tools and check if each javascript chunk is loaded the first time you visit a route:
Now it's time to learn by doing.
Try to complete next steps on your own:
a) Create a new route, as done before, named login
.
b) Update the routing rules in order to load the login
route when users visit the "index" path: http://localhost:4200/
Update AppRoutingModule
: the "login" page should be shown when the path
is an empty string:
{ path: '', ... }
a) Create a new SharedModule
in /app/shared
ng g m shared
b) Create a new component CardComponent
in the shared
folder, add it to SharedModule
and export it in order to be used elsewhere.
You can automatically accomplish it by using the following command:
ng g c shared/components/card --flat --export
--flat
to avoid the card folder creation--export
to add component in both, declarations
and exports
properties, of SharedModule
c) Now you can use the CardComponent
component in HomeComponent
.
Import SharedModule
in HomeModule
, so you can use <app-card>
component in your HomeComponent
HTML template.
d) Test your work. Open http://localhost:4200/home
and you should see following output:
Add a new component to SharedModule
, named IconComponent
, as done in the previous exercise, and use it in users.component.ts
.
Here you can see the final result: