Routing in Angular

Diagram of circles and lines meant indicative of routing in Angular.

Routing in Angular is a key component of the framework. For me, it’s usually one of the first things I do during development. It enables me to quickly build a foundation. The applications I work on typically have an innumerable amount of moving parts, so I incorporate modules. Modularity often causes complexity. Usually, there’s features such as components that are isolated to certain areas. These components are housed in prospective modules.

Git Repo

I’ve worked with devs who don’t understand the purpose of modules. One may think of them as packages in Spring. Or akin to micro-services in large applications. They’re collections of features and related code. They’re ways to isolate content and enable loading thereof at designated times. Conceptually known as Lazy Loading.

Lazy Loading

Lazy loading is a feature indicative of loading assets on a need to know basis. In a single page application, there could be dozens of features. Most of which are not needed when the user initially lands on the home page. Or, whatever page. There’s no point in making the user wait for thereof to be loaded. So, aforementioned assets are loaded if and only if the user visits that page. It’s the opposite of formerly popular website loaders with nifty animations. These systems would show a percentage and often times load everything up front. Frontend frameworks such as Angular, Vue, and React have more robust systems enabling devs to simply improve UX.

Every app has at least one module—called the root module. This class uses a function called a decorator that lets the framework know, it’s special. The function takes one object with properties. Popular properties are imports, exports, declarations, and providers. Imports contain other modules. Declarations are the components used in that module. Exports are items you may wish to make available to other modules. All of which are arrays. Be careful however not to replicate import statements. Avoid this like so:

// Router
import { ComponentOne } ...
import { ComponentTwo } ...
import { ComponentThree } ...
    
const routes: Routes = [
   { path: '...', component: ComponentOne   },
   { path: '...', component: ComponentTwo   },
   { path: '...', component: ComponentThree },
];
    
@NgModule({
   imports: [RouterModule.forChild(routes)],
   exports: [RouterModule],
})

export class SampleRouterModule {} 
export const routerComponents = [ComponentOne, ComponentTwo, ComponentThree];

// Module
// Import Cmpts vs Duplicate Statements
import { SampleRouterModule, routerComponents } from './sample-route.routing';

@NgModule({
  declarations: [routerComponents],
  imports: [CommonModule, ModuleOneRoutingModule],
})

export class SampleModule {}

Routing in Angular

Page navigation can no doubt be done a variety of ways. The router however is undoubtedly the best option. This is what ultimately makes these frameworks so popular. They’re elegant, can be faster than conventionally built sites. And perhaps most importantly, they function like mobile applications. Mobile apps, in that there’s no flash between pages. This is because we’re swapping out the content inside a static shell. All of which emanates from the router. It is in the router that we dictate the page names and their destination. Typically, we’d do something like this:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  { path: 'module-one', component: 'SomeComponent' }
];

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

Navigating to components in this manner loads them all simultaneously though. Modules will also be eager to load on startup. We can change this scenario via loadChildren, which activates Lazy Loading.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
    
const routes: Routes = [
  {
    path: 'feature-module',
    loadChildren: () => import('./feature-module.module').then((m) => m.ModuleOneModule)
  }
];

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

The Feature Module then looks like this:

// Feature Module
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
    
const routes: Routes = [
  {
    path: '',
    component: FeatureComponent,
    children: [{ path: 'my-route', component: FeatureComponent }],
  },
];
    
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class FeatureRoutingModule {}

Not every app though has modules. Or the need for them. If you wanted to simply route to components, and include child routes too, it’d look like this. Not too complicated, right? Check out the code here.

const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'about',
    component: AboutComponent,
    children: [
      { path: '', component: EmployeesComponent },
      { path: 'employees', component: EmployeesComponent },
      { path: 'goals', component: GoalsComponent },
      { path: 'services', component: ServicesComponent },
    ],
  },
  { path: 'products', component: ProductsComponent },
  { path: 'contact', component: ContactComponent },
];

Frontend frameworks such as Angular are shockingly powerful, flexible, and robust. Angular has a massive library of classes. Therefore, whatever the need, there’s most likely inbuilt support for it. Other frameworks require third party systems to do what Angular comes fully equipped with. But I digress. Check out the Stackblitz if you’re stuck or want to tinker with the code. Hope you’ve enjoyed this brief post on routing in Angular.

Be the first to comment

Leave a Reply

Your email address will not be published.


*