<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kimani</title>
    <description>The latest articles on Forem by Kimani (@elviskim18).</description>
    <link>https://forem.com/elviskim18</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F873358%2Fc993abeb-c1f5-4b6e-b04b-d24a0d0fa1b4.png</url>
      <title>Forem: Kimani</title>
      <link>https://forem.com/elviskim18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/elviskim18"/>
    <language>en</language>
    <item>
      <title>Role-Based Multi-Tenant Fron-tend Architecture in Angular</title>
      <dc:creator>Kimani</dc:creator>
      <pubDate>Mon, 11 Aug 2025 13:16:24 +0000</pubDate>
      <link>https://forem.com/elviskim18/role-based-multi-tenant-fron-tend-architecture-in-angular-4mg2</link>
      <guid>https://forem.com/elviskim18/role-based-multi-tenant-fron-tend-architecture-in-angular-4mg2</guid>
      <description>&lt;p&gt;Whenever we hear the term &lt;strong&gt;multi-tenant architecture&lt;/strong&gt;, our minds often go straight to traditional SaaS products—where a single application instance serves &lt;strong&gt;multiple clients or organizations&lt;/strong&gt; (tenants), each with isolated data and, in some cases, customized themes or domains. A classic example is Slack, where each workspace acts as an independent tenant within the platform.&lt;/p&gt;

&lt;p&gt;However, there’s an &lt;strong&gt;equally important but less-discussed perspective&lt;/strong&gt; on multi-tenancy: designing applications that support &lt;strong&gt;multiple user roles within a single organization&lt;/strong&gt;, each with a tailored user experience.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how to build a &lt;strong&gt;role-based multi-tenant front-end&lt;/strong&gt; using Angular, where different user types access the same application but see different interfaces, components, and routes—all within a single codebase.&lt;/p&gt;

&lt;p&gt;Imagine a retail management platform with three distinct user roles:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Country Manager&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Views national performance dashboards&lt;/li&gt;
&lt;li&gt;Compares regional performance&lt;/li&gt;
&lt;li&gt;Accesses financial reports&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Regional Manager&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Monitors stores within their assigned region&lt;/li&gt;
&lt;li&gt;Views regional KPIs&lt;/li&gt;
&lt;li&gt;Compares store-level performance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Field Member&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Records daily store operations&lt;/li&gt;
&lt;li&gt;Logs inventory counts&lt;/li&gt;
&lt;li&gt;Views task assignments and reports&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rather than building three separate applications for each role—which would be costly and hard to maintain—the ideal solution is a single Angular application where all users log in through the same entry point (URL), but are presented with role-specific experiences tailored to their responsibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Achieve This in Angular?
&lt;/h2&gt;

&lt;p&gt;We'll implement this architecture using a combination of Angular concepts and best practices, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dynamic component rendering&lt;/strong&gt;&lt;br&gt;
Show or hide UI elements based on the user's role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Role-based lazy loading&lt;/strong&gt;&lt;br&gt;
Load only the modules and components needed for the current user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hierarchical service patterns&lt;/strong&gt;&lt;br&gt;
Structure shared vs role-specific logic cleanly across services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Route guards&lt;/strong&gt;&lt;br&gt;
Restrict access to routes based on user roles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we begin, make sure you have the following tools installed and ready to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node.js and npm&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular requires Node.js to run. You can verify if it's installed by running the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Angular CLI&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Angular CLI is the command-line tool used to create, serve, and manage Angular applications.To install it globally, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @angular/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then confirm the installation with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 Recommended: Use Angular version 16+ for best compatibility with the features used in this guide&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a New Angular App
&lt;/h2&gt;

&lt;p&gt;With the prerequisites installed, let’s scaffold a fresh Angular project that we’ll use to build our role-based multi-tenant UI.&lt;br&gt;
Run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new role-based-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a Mock Login Page
&lt;/h2&gt;

&lt;p&gt;Before we define routes and dashboards, let’s build a simple login page that lets us simulate signing in as a Country Manager, Regional Manager, or Field Agent. This won't involve any real authentication—instead, we'll just store the selected user role and use it to load role-specific content&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create the Login Component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generate the component using Angular CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Design the Login UI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Update login.component.html with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="container-fluid w-25 mx-auto d-flex flex-column gap-3"&amp;gt;
    &amp;lt;div class="mt-5"&amp;gt;
        &amp;lt;div class="fs-4 fw-medium"&amp;gt;Sign in&amp;lt;/div&amp;gt;
        &amp;lt;div class="text-secondary s-font"&amp;gt;Please choose an account to sign in&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="d-flex flex-row align-items-center gap-2"&amp;gt;
         &amp;lt;div&amp;gt;&amp;lt;button type="button" class="btn btn-primary text-nowrap" (click)="login('COUNTRY_MANAGER')"&amp;gt;General Manager&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;
         &amp;lt;div&amp;gt;&amp;lt;button type="button" class="btn btn-warning text-nowrap" (click)="login('REGIONAL_MANAGER')"&amp;gt;Regional Manager&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;
         &amp;lt;div&amp;gt;&amp;lt;button type="button" class="btn btn-success text-nowrap" (click)="login('FIELD_MEMBER')"&amp;gt;Field Agent&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Handle Login Logic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In login.component.ts, use a mock AuthService to store the selected role and redirect the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component } from '@angular/core';
import { AuthenticationService } from '../../app/services/authentication.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  imports: [],
  templateUrl: './login.component.html',
  styleUrl: './login.component.scss'
})
export class LoginComponent {

  constructor(private authService: AuthenticationService, private router: Router) {}

  login(role: 'COUNTRY_MANAGER' | 'REGIONAL_MANAGER' | 'FIELD_MEMBER') {
    this.authService.setRole(role);

    // Navigate based on role
    switch (role) {
      case 'COUNTRY_MANAGER':
        this.router.navigate(['/manager']);
        break;
      case 'REGIONAL_MANAGER':
        this.router.navigate(['/regional']);
        break;
      case 'FIELD_MEMBER':
        this.router.navigate(['/field']);
        break;
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the AuthService
&lt;/h2&gt;

&lt;p&gt;Now lets create a simple role manager service:&lt;/p&gt;

&lt;p&gt;📁 src/app/services/auth.service.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Injectable } from '@angular/core';
export type UserRole = 'COUNTRY_MANAGER' | 'REGIONAL_MANAGER' | 'FIELD_MEMBER';

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {
  private role: UserRole | null = null;


  constructor() { }

  setRole(role: UserRole) {
    this.role = role;
    localStorage.setItem('user_role', role);
  }

  getRole(): UserRole | null {
    return this.role || (localStorage.getItem('user_role') as UserRole);
  }

  clearRole() {
    this.role = null;
    localStorage.removeItem('user_role');
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up Modules for Each User Role
&lt;/h2&gt;

&lt;p&gt;Now that we’ve created the login page and a simple AuthService to simulate role-based sign-in, it’s time to create separate modules for each user type.&lt;/p&gt;

&lt;p&gt;This will allow us to keep things modular and enable lazy loading for better performance and maintainability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Generate the Feature Modules&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll create a module for each role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module modules/manager --routing 
ng generate module modules/regional --routing 
ng generate module modules/field --routing

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these commands generates a new module and sets up routing for it. Now your folder structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app/
│   ├── modules/
│   │   ├── manager/
│   │   ├── regional/
│   │   └── field/
│   ├── login/
│   ├── services/
│   └── app-routing.module.ts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Create Components for Each Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve generated the manager, regional, and field modules, let’s create the core components inside each of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧱 For the Manager Module, run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component modules/manager/components/home
ng generate component modules/manager/components/manager-nav
ng generate component modules/manager/components/manage-regions
ng generate component modules/manager/components/manage-regional-managers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create four components to structure the manager’s experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HomeComponent&lt;/strong&gt;: Dashboard or landing page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ManagerNavComponent&lt;/strong&gt;: &lt;br&gt;
Container or layout that holds child     routes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ManageRegionsComponent&lt;/strong&gt;: Handles region management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ManageRegionalManagersComponent&lt;/strong&gt;: &lt;br&gt;
Handles regional manager assignments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can follow the same process for regional and field modules with components relevant to their roles&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Set Up Routing for the Manager Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let’s wire up routing within the Manager module using child routes and a container component (ManagerNavComponent).&lt;/p&gt;

&lt;p&gt;Here's the complete routing config for the Manager module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// features/manager/manager-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { ManageRegionsComponent } from './components/manage-regions/manage-regions.component';
import { ManageRegionalManagersComponent } from './components/manage-regional-managers/manage-regional-managers.component';
import { ManagerNavComponent } from './components/manager-nav/manager-nav.component';
import { roleDataResolver } from '../../app/resolvers/role-data.resolver';

const routes: Routes = [
  {
    path: '',
    component: ManagerNavComponent,
    children: [
      { path: '', component: HomeComponent },
      {
        path: 'admins',
        component: ManageRegionalManagersComponent,

      },
      {
        path: 'towns',
        component: ManageRegionsComponent,
      }
    ]
  }
];

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

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt;:ManagerNavComponent acts as a layout shell (e.g., with a side nav or topbar)&lt;/p&gt;

&lt;p&gt;Perfect! Now that we've set up our manager, regional, and field modules with their own routing and components, let's move on to the main AppRoutingModule, which acts as the central router for lazy-loading the appropriate module based on user role.&lt;/p&gt;

&lt;h2&gt;
  
  
  App Routing Setup
&lt;/h2&gt;

&lt;p&gt;We’ll configure app-routing.module.ts to lazy-load each module (manager, regional, field) when a user logs in. &lt;/p&gt;

&lt;p&gt;📁 app-routing.module.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Routes } from '@angular/router';
import { LoginComponent } from '../pages/login/login.component';
import { NotFoundComponent } from '../pages/not-found/not-found.component';
import { MainnavComponent } from './mainnav/mainnav.component';
import { roleDataResolver } from './resolvers/role-data.resolver';
import { roleGuard } from './guards/role.guard';

export const routes: Routes = [
    { path: '', component: LoginComponent },
    { path: 'login', component: LoginComponent },
    {
        path: 'manager',component: MainnavComponent,
        loadChildren: () =&amp;gt; import('../modules/general-manager/general-manager.module').then(m =&amp;gt; m.GeneralManagerModule),
        resolve: { roleData: roleDataResolver },
        canActivate: [roleGuard],
        data: { role: 'COUNTRY_MANAGER' }
    },
    {
        path: 'regional',component: MainnavComponent,
        loadChildren: () =&amp;gt; import('../modules/regional-manager/regional-manager.module').then(m =&amp;gt; m.RegionalManagerModule),
        resolve: { roleData: roleDataResolver },
        canActivate: [roleGuard],
        data: { role: 'REGIONAL_MANAGER' }
    },
    {
        path: 'field',component: MainnavComponent,
        loadChildren: () =&amp;gt; import('../modules/field-member/field-member.module').then(m =&amp;gt; m.FieldMemberModule),
        resolve: { roleData: roleDataResolver },
        canActivate: [roleGuard],
        data: { role: 'FIELD_MEMBER' }
    },
  { path: '**', component: NotFoundComponent },


];

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔐 Setting Up Role-Based Guard
&lt;/h2&gt;

&lt;p&gt;After setting up the routed we'll create a single flexible role guard called roleGuard, which will restrict access to certain routes based on the logged-in user's role.&lt;/p&gt;

&lt;p&gt;📁 app/guards/role.guard.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router';
import { AuthenticationService } from '../services/authentication.service';

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

export const roleGuard: CanActivateFn = (route, state) =&amp;gt; {
  const auth = inject(AuthenticationService);
  const router = inject(Router);

   const expectedRole = route.data['role'];
    if (auth.getRole() === expectedRole) {
      console.log(`Access granted for role: ${expectedRole}`);
      return true;
    }
    router.navigate(['/login']);
    console.log(`Access denied for role`);
    return false;
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the guard in place, you now have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralized role-based route protection&lt;/li&gt;
&lt;li&gt;Clean routing using data to define role access&lt;/li&gt;
&lt;li&gt;A dynamic and scalable guard strategy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📡 Simulating Real-World Data with Resolvers
&lt;/h2&gt;

&lt;p&gt;To test our app with realistic role-specific content, we'll simulate backend data using Angular resolvers and mock data services. This helps mimic what would typically come from an API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1. Mock API Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's begin by creating a mock data source. Inside the mockup-api/ folder, create a data.ts file that exports structured sample data for each user type:&lt;/p&gt;

&lt;p&gt;📁 mockup-api/data.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { countryManager, fieldMembers, regionalManager } from "../models/platform-model";

export const regionalManagerData: regionalManager = {
  name: 'Gabriel Wainaina',
  top_member: 'Alice Mwangi',
  total_orders: 15000,
  order_target: 20000,
  outlet_visitations: 5,
  stores: [
    { name: 'Quickmart Nairobi', location: 'Nairobi', assignedMember: 'Alice Mwangi' },
    { name: 'Naivas Westlands', location: 'Nairobi', assignedMember: 'Bob Otieno' },
    { name: 'Cleanshelf Thika', location: 'Nairobi', assignedMember: 'Catherine Wambui' }
  ],
  schedules: [
    { name: 'Naivas Westlands', date: '2025-07-30', time: '10:00 AM' },
    { name: 'Cleanshelf Thika', date: '2025-08-01' }
  ],
  region: 'Nairobi',

  field_members: [
    { name: 'Alice Mwangi', assignedStores: 5, assignedVisits: [
      { store: 'Quickmart Ngara', status: 'completed' },
      { store: 'Naivas Westlands', status: 'pending' },
      { store: 'Cleanshelf Thika', status: 'completed' }
    ], task_completion_rate: 90 },
    { name: 'Bob Otieno', assignedStores: 4, assignedVisits: [
      { store: 'Quickmart Malaba', status: 'completed' },
      { store: 'Naivas Nakuru', status: 'pending' },
    ] , task_completion_rate: 85 },
    { name: 'Catherine Wambui', assignedStores: 6, assignedVisits: [
      { store: 'Quickmart Nairobi', status: 'completed' },
      { store: 'Naivas Juja', status: 'pending' },
    ], task_completion_rate: 95 }
  ],  

};

export const countryManagerData:countryManager = {
  name: 'John Doe',
  regions:[
    { name:'Nairobi', manager:'John Doe'},
    { name:'Kakamega', manager:'Bien Aime'},
    { name:'Kisumu', manager:'Coster Ojwang'},
    { name:'Nakuru', manager:'Bobby Doe'}
  ],
  managers:[
    {
      name: 'John Doe',
      region: 'Nairobi',
      field_members: [],
      top_member: 'Bruce Lee',
      total_orders: 30450,
      order_target: 25000,
      outlet_visitations: 10,
      stores: [],
      schedules: []
    },
    {
      name: 'Bien Aime',
      region: 'Kakamega',
      field_members: [],
      top_member: 'Mark Twight',
      total_orders: 45000,
      order_target: 25000,
      outlet_visitations: 8,
      stores: [],
      schedules: []
    },
     {
      name: 'Coster Ojwang',
      region: 'Kisumu',
      field_members: [],
      top_member: 'Liam Wayne',
      total_orders: 22450,
      order_target: 25000,
      outlet_visitations: 8,
      stores: [],
      schedules: []
    },
  ],
  top_performing_region:'Nairobi',
  total_order_value:150000,
  monthly_order_target:2000000,
  total_outlet_visitations:400


};
export const fieldAgentData:fieldMembers = {
  name: 'Lewis Hamilton',
  assignedVisits: [
    { store: 'Quickmart Nairobi', status: 'completed' },
    { store: 'Naivas Westlands', status: 'pending' },
    { store: 'Cleanshelf Thika', status: 'pending' }
  ],
  assignedStores: 3,
  task_completion_rate: 75,
  todays_completed_tasks: 2,
  todays_total_tasks: 3,
  todays_order_value: 50000,
  todays_visitations: 1,
  todays_schedule: [
    { store: 'Quickmart Nairobi', date: '2025-07-30', startTime: '10:00 AM', endTime: '11:00 AM' },
    { store: 'Naivas Westlands', date: '2025-07-30', startTime: '12:00 PM', endTime: '1:00 PM' },
    { store: 'Cleanshelf Thika', date: '2025-07-30', startTime: '2:00 PM', endTime: '3:00 PM' }
  ]

};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2. Define Interfaces for Type Safety&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In models/platform-model.ts, add TypeScript interfaces to describe the structure of each role's data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface PlatformModel {
}
export interface countryManager {
    name: string,
    regions:Array&amp;lt;any&amp;gt;,
    managers:Array&amp;lt;regionalManager&amp;gt;,
    top_performing_region:string,
    total_order_value:number,
    monthly_order_target:number,
    total_outlet_visitations:number
}

export interface regionalManager {
    name:string,
    region:string,
    field_members:Array&amp;lt;fieldMembers&amp;gt;
    top_member:string,
    total_orders:number,
    order_target:number,
    outlet_visitations:number
    stores:Array&amp;lt;any&amp;gt;
    schedules:Array&amp;lt;any&amp;gt;


}

export interface fieldMembers {
    name:string,
    assignedStores:number,
    assignedVisits:Array&amp;lt;any&amp;gt;,
    task_completion_rate:number,
    todays_completed_tasks?:number,
    todays_total_tasks?:number,
    todays_order_value?:number,
    todays_visitations?:number,
    todays_schedule?:Array&amp;lt;any&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3. Create the Resolver&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Resolvers in Angular fetch data before navigating to a route. Ours will use the authenticated user’s role to return the right mock data&lt;/p&gt;

&lt;p&gt;📁 resolvers/role-data-resolver.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { RoleDataService } from '../services/role-data.service';
import { AuthenticationService } from '../services/authentication.service';

export const roleDataResolver: ResolveFn&amp;lt;any&amp;gt; = (route, state) =&amp;gt; {
  console.log(route.data)
  let auth: AuthenticationService = inject(AuthenticationService);

  const role = auth.getRole() ?? '';
  console.log(role)
  return inject(RoleDataService).getData(role);
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4. RoleDataService to Return Mock Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a service that maps roles to mock data:&lt;/p&gt;

&lt;p&gt;📁 services/role-data.service.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Injectable } from '@angular/core';
import { countryManagerData, fieldAgentData, regionalManagerData } from '../mock-api/data';

@Injectable({
  providedIn: 'root'
})
export class RoleDataService {

  constructor() { }

  getData(role: string) {
    switch (role) {
      case 'COUNTRY_MANAGER':
        return countryManagerData;
      case 'REGIONAL_MANAGER':
        return regionalManagerData;
      case 'FIELD_MEMBER':
        return fieldAgentData;
      default:
        return null;
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Step 5. Use the Resolver in Routes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Where appropriate (usually in role-specific modules), add the resolver to fetch data:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; – In manager-routing.module.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes: Routes = [
  {
    path: '',
    component: ManagerNavComponent,
    children: [
      {
        path: '',
        component: HomeComponent,
        resolve: { roleData: roleDataResolver }
      },
      {
        path: 'admins',
        component: ManageRegionalManagersComponent,
        resolve: { roleData: roleDataResolver }
      },
      {
        path: 'towns',
        component: ManageRegionsComponent,
        resolve: { roleData: roleDataResolver }
      }
    ]
  }
];

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup ensures that each route fetches the appropriate user-specific data before the component renders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying Resolved Data in a Component
&lt;/h2&gt;

&lt;p&gt;With our route resolver (roleDataResolver) and guards in place,let's demonstrate how we can consume the resolved data inside a component. We'll use the ManageRegionalManagersComponent as an example, where we fetch a list of managers and display them in a table.&lt;/p&gt;

&lt;p&gt;manage-regional-managers.component.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component } from '@angular/core';
import { countryManager } from '../../../../app/models/platform-model';
import { ActivatedRoute } from '@angular/router';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-manage-regional-managers',
  imports: [CommonModule],
  templateUrl: './manage-regional-managers.component.html',
  styleUrl: './manage-regional-managers.component.scss'
})
export class ManageRegionalManagersComponent {
  data!: countryManager;

  constructor(private route: ActivatedRoute) {}

  ngOnInit(): void {
    this.data = this.route.snapshot.data['roleData'];
    console.log(this.data);
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the component uses Angular's ActivatedRoute to retrieve the resolved roleData from the route and stores it in a data variable. This approach ensures that the data is already available when the component loads — no need to wait for an asynchronous call here.&lt;/p&gt;

&lt;p&gt;📁 manage-regional-managers.component.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="container-fluid ps-5 pt-3"&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;div class="fs-3"&amp;gt;Managers&amp;lt;/div&amp;gt;
    &amp;lt;div class="pt-2 text-body-tertiary s-font"&amp;gt;
      Manage your managers here
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div class="mt-5 border p-3 rounded"&amp;gt;
    &amp;lt;div&amp;gt;List of Managers&amp;lt;/div&amp;gt;
    &amp;lt;div class="mt-3"&amp;gt;
      &amp;lt;table class="table table-responsive table-borderless table-hover align-middle"&amp;gt;
        &amp;lt;thead class="border-bottom border-light-subtle"&amp;gt;
          &amp;lt;tr&amp;gt;
            &amp;lt;th scope="col"&amp;gt;#&amp;lt;/th&amp;gt;
            &amp;lt;th scope="col"&amp;gt;Manager&amp;lt;/th&amp;gt;
            &amp;lt;th scope="col"&amp;gt;Region&amp;lt;/th&amp;gt;
            &amp;lt;th scope="col"&amp;gt;Manage&amp;lt;/th&amp;gt;
            &amp;lt;th scope="col"&amp;gt;Manage&amp;lt;/th&amp;gt;
          &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
          &amp;lt;tr *ngFor="let manager of data.managers; let i = index"&amp;gt;
            &amp;lt;th scope="row"&amp;gt;{{ i + 1 }}&amp;lt;/th&amp;gt;
            &amp;lt;td class="text-secondary"&amp;gt;{{ manager.name }}&amp;lt;/td&amp;gt;
            &amp;lt;td class="text-secondary"&amp;gt;{{ manager.region }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;button class="btn btn-outline-secondary btn-sm"&amp;gt;Edit&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;button class="btn btn-outline-warning btn-sm"&amp;gt;Delete&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
          &amp;lt;/tr&amp;gt;
        &amp;lt;/tbody&amp;gt;
      &amp;lt;/table&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After following the above steps, this is how your Login Page and the three different Dashboards (General Manager, Regional Manager, and Field Member) will look.&lt;/p&gt;

&lt;h4&gt;
  
  
  Login
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1m8m4o791iaaisav2iyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1m8m4o791iaaisav2iyl.png" alt="Login page" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Field Member
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6pn2xem1jyjs94vrc94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6pn2xem1jyjs94vrc94.png" alt="field member dashboard" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Regional Manager
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnc5pihjemuk9ppqfzbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnc5pihjemuk9ppqfzbr.png" alt="regional manager dashboard" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  General Manager
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhd3wla3755z6j9he2jqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhd3wla3755z6j9he2jqq.png" alt="general manager dashboard" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this guide, we walked through the process of building a Role-Based Multi-Tenant Front-end Architecture in Angular. We started by setting up a login flow to mimic authentication for three different user types, then created dedicated dashboards for each role. We implemented modular routing to keep features organized and maintainable, laying the groundwork for adding guards and other access-control mechanisms.&lt;/p&gt;

&lt;p&gt;This architecture ensures that each user role has a tailored experience, improves security by restricting access to certain routes, and keeps the codebase scalable as new roles or modules are introduced.&lt;/p&gt;

&lt;p&gt;You can access the full codebase by cloning the repository on &lt;a href="https://github.com/elviskim18/Multi-tenant-UI-in-Angular--Demo.git" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now it’s your turn to build and customize your own role-based multi-tenant Angular app!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What is Apache Camel</title>
      <dc:creator>Kimani</dc:creator>
      <pubDate>Wed, 29 Mar 2023 05:35:31 +0000</pubDate>
      <link>https://forem.com/elviskim18/what-is-apache-camel-3bcd</link>
      <guid>https://forem.com/elviskim18/what-is-apache-camel-3bcd</guid>
      <description>&lt;p&gt;Apache Camel is an open-source integration framework that provides a lightweight and flexible way to integrate various systems and technologies. With Camel, developers can easily build integration solutions using a variety of programming languages, message formats, and protocols. Well one might ask what do we mean by integration solutions.&lt;br&gt;
Integration solutions refer to the process of connecting different systems or technologies together so that they can exchange information and work together seamlessly. In today's technology landscape, it's common for organizations to use multiple systems and applications to support their business processes. For example, a company might use one system for customer relationship management (CRM), another for supply chain management, and yet another for financial management.&lt;/p&gt;

&lt;p&gt;Integration solutions are needed to ensure that these systems can communicate and share data with each other effectively. This can involve tasks such as data mapping, transformation, and synchronization, as well as the implementation of protocols and standards for exchanging data between systems. Integration solutions can be implemented using middleware tools such as Apache Camel, which provides a set of patterns and components for connecting different systems and technologies together.&lt;/p&gt;

&lt;p&gt;By implementing integration solutions, organizations can improve their operational efficiency, reduce data inconsistencies, and provide a better experience for both internal and external stakeholders. For example, integration solutions can enable a company to provide a single view of customer data across multiple systems, reducing the need for manual data entry and improving the accuracy of data. Integration solutions can also enable real-time data processing and analysis, enabling companies to make better decisions based on up-to-date information.&lt;/p&gt;

&lt;p&gt;Overall, if you are new to Apache Camel, it may take some time to get up to speed with its concepts and patterns. However, if you are interested in building integration solutions or messaging architectures, Camel can be a powerful tool that can help you build complex systems in a flexible and maintainable way.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is a Serverless Architecture?</title>
      <dc:creator>Kimani</dc:creator>
      <pubDate>Fri, 27 Jan 2023 16:43:46 +0000</pubDate>
      <link>https://forem.com/elviskim18/what-is-a-serverless-architecture-ci6</link>
      <guid>https://forem.com/elviskim18/what-is-a-serverless-architecture-ci6</guid>
      <description>&lt;p&gt;They say if you can't explain something to a kid you probably don't understand it yourself…right? I am sure they said that LOL!. Okay so in the simplest terms Serverless architecture is a way of building and running things like websites or apps where you don't have to worry about the underlying infrastructure, such as servers, and you can scale and adjust automatically as needed. &lt;/p&gt;

&lt;p&gt;Serverless architecture allows applications to be hostless ie not hosted on a server. This means that instead of having to provision and maintain servers, you can simply run your code in response to events and automatically scale as needed.&lt;/p&gt;

&lt;p&gt;Examples of services that use serverless architecture include AWS Lambda, Azure Functions, and Google Cloud Functions. These services allow you to run your code in response to events such as an HTTP request, a message on a message queue, or a change in a database, and automatically manage the underlying infrastructure for you. This can include things like automatic scaling, patching, and security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Well you may ask what is the alternative to a serverless architecture?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The main alternative to serverless architecture is a traditional, or "serverful," architecture. In this approach, you would provision and manage your own servers, or use a virtualized infrastructure, such as a cloud-based virtual machine (VM), to run your applications and services. This approach gives you more control over the underlying infrastructure, but also requires you to manage and maintain that infrastructure, including tasks such as scaling, patching, and security.&lt;br&gt;
In a traditional architecture, you would typically use a web server such as Apache or Nginx to handle HTTP requests and an application server such as Tomcat or Node.js to handle application logic. You would also have to manage the underlying operating system, including security updates, and scaling the infrastructure up or down as needed.&lt;br&gt;
Another alternative to Serverless is Container-based architecture, where you would package your applications and services as container images, and run them on a container orchestration platform such as Kubernetes or Docker Swarm. This gives you many of the benefits of serverless, such as automatic scaling and patching, but also gives you more control over the underlying infrastructure than serverless.&lt;/p&gt;

&lt;p&gt;In summary, the main alternative to serverless architecture is traditional, or "serverful," architecture, where you would provision and manage your own servers or use a virtualized infrastructure to run your applications and services. Another alternative is Container-based architecture, which gives you many of the benefits of serverless but also gives you more control over the underlying infrastructure.&lt;/p&gt;

&lt;p&gt;I know I have taken you down the little rabbit hole there for a minute but I hope we have come out the other end together alright. &lt;br&gt;
Thank you and stay tuned for more&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Angular Router Events Lifecycle</title>
      <dc:creator>Kimani</dc:creator>
      <pubDate>Sat, 07 Jan 2023 20:17:27 +0000</pubDate>
      <link>https://forem.com/elviskim18/angular-router-events-lifecycle-4l7g</link>
      <guid>https://forem.com/elviskim18/angular-router-events-lifecycle-4l7g</guid>
      <description>&lt;p&gt;Have you ever wondered what happens when you hit a link in an Angular application? Well this is just the right article for you. In Angular, the router is an essential component that is responsible for managing the application's navigation. It helps to navigate between different components of the application and keep the application in sync with the current URL. The router emits several events at different stages of the routing process, which allow you to track the lifecycle of the router and perform actions or modify the behavior of the router.&lt;/p&gt;

&lt;p&gt;The sequence in which router events occur is as follows:&lt;br&gt;
.NavigationStart&lt;br&gt;
.RouteConfigLoadStart&lt;br&gt;
.RouteConfigLoadEnd&lt;br&gt;
.RoutesRecognized&lt;br&gt;
.GuardsCheckStart&lt;br&gt;
.ChildActivationStart&lt;br&gt;
.ActivationStart&lt;br&gt;
.GuardsCheckEnd&lt;br&gt;
.ResolveStart&lt;br&gt;
.ResolveEnd&lt;br&gt;
.ActivationEnd&lt;br&gt;
.ChildActivationEnd&lt;br&gt;
.NavigationEnd&lt;br&gt;
.NavigationCancel&lt;br&gt;
.NavigationError&lt;br&gt;
.Scroll&lt;/p&gt;

&lt;p&gt;I know what your thinking "Whoa!! That's a lot". Do not worry we'll go through each and everyone for better comprehension.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NavigationStart&lt;/strong&gt;&lt;br&gt;
This event is emitted when a new navigation is initiated. This event can be used to set a loading indicator or display a message to the user indicating that the application is navigating to a new route. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, NavigationStart } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof NavigationStart) {
      // Show a loading indicator or display a message
    }
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RouteConfigLoadStart&lt;/strong&gt;&lt;br&gt;
This event is emitted when the router begins to load a route configuration. This event can be used to display a loading indicator or perform other tasks while the route configuration is being loaded. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, RouteConfigLoadStart } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof RouteConfigLoadStart) {
      // Show a loading indicator or perform other tasks
    }
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RouteConfigLoadEnd&lt;/strong&gt;&lt;br&gt;
When the router finishes loading a route configuration, it emits the RouteConfigLoadEnd event. This event can be used to hide a loading indicator or perform other tasks after the route configuration has been loaded. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, RouteConfigLoadEnd } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof RouteConfigLoadEnd) {
      // Hide a loading indicator or perform other tasks
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RoutesRecognized&lt;/strong&gt;&lt;br&gt;
This event is emitted when the router recognizes a route change. It marks the beginning of the route recognition process and can be used to perform tasks before the router begins to update the route. If the matched path requires a lazy loaded module, it will be loaded at this point.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lazy loading is a technique that allows you to load modules or components on demand, rather than loading them upfront. This can help to improve the performance of your Angular application, especially if it is a large application with many components.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, RoutesRecognized } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof RoutesRecognized) {
      // Perform tasks before the router begins to update the route
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GuardsCheckStart&lt;/strong&gt;&lt;br&gt;
The GuardsCheckStart event is emitted when the router starts running route guards. Route guards are functions that can be used to protect access to a route or to modify the behavior of the router. They are run before the router activates a route and can prevent the router from navigating to the route if necessary. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, GuardsCheckStart } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof GuardsCheckStart) {
      // Perform tasks before route guards are run
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ChildActivationStart&lt;/strong&gt;&lt;br&gt;
The ChildActivationStart event is emitted when the router starts activating a child route. It can be used to perform tasks before a child route is activated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, ChildActivationStart } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof ChildActivationStart) {
      // Perform tasks before a child route is activated
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ActivationStart&lt;/strong&gt;&lt;br&gt;
This event is emitted when the router starts activating a route. It can be used to perform tasks before a route is activated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, ActivationStart } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof ActivationStart) {
      // Perform tasks before a route is activated
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GuardsCheckEnd&lt;/strong&gt;&lt;br&gt;
Finally the &lt;em&gt;GuardsCheckEnd&lt;/em&gt; event is emitted when the router finishes running route guards. It can be used to perform tasks after route guards have been run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, GuardsCheckEnd } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof GuardsCheckEnd) {
      // Perform tasks after route guards have been run
    }
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the guard has passed, the router has answered its second question, “Should I perform this navigation?”. The router can now prefetch any data using route resolvers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ResolveStart&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;ResolveStart&lt;/em&gt; event is emitted when the router starts running route resolvers. Route resolvers are functions that can be used to pre-fetch data for a route. They are run before the route is activated and can be used to ensure that the route has all the necessary data when it is displayed to the user. Foe example;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, ResolveStart } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof ResolveStart) {
      // Perform tasks before route resolvers are run
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ResolveEnd&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;ResolveEnd&lt;/em&gt; event is emitted when the router finishes running route resolvers. It can be used to perform tasks after route resolvers have been run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, ResolveEnd } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof ResolveEnd) {
      // Perform tasks after route resolvers have been run
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ActivationEnd&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;ActivationEnd&lt;/em&gt; event is emitted when the router finishes activating a route. It can be used to perform tasks after a route has been activated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, ActivationEnd } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof ActivationEnd) {
      // Perform tasks after a route has been activated
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ChildActivationEnd&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;ChildActivationEnd&lt;/em&gt; event is emitted when the router finishes activating a child route. It can be used to perform tasks after a child route has been activated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, ChildActivationEnd } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof ChildActivationEnd) {
      // Perform tasks after a child route has been activated
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NavigationEnd&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;NavigationEnd&lt;/em&gt; event is emitted when the navigation is complete. It can be used to update the application's state or perform other tasks after the navigation has completed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, NavigationEnd } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof NavigationEnd) {
      // Update the application's state or perform other tasks
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NavigationCancel&lt;/strong&gt;&lt;br&gt;
If the navigation is cancelled, the router emits the &lt;em&gt;NavigationCancel&lt;/em&gt; event. This can happen if the router is unable to match the current URL to a route or if the navigation is explicitly cancelled by calling the router.navigate() method with the cancel option set to true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, NavigationCancel } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof NavigationCancel) {
      // Perform tasks in response to the navigation being cancelled
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NavigationError&lt;/strong&gt;&lt;br&gt;
If an error occurs during the navigation process, the router emits the &lt;em&gt;NavigationError&lt;/em&gt; event. This event can be used to display an error message or perform other tasks when an error occurs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, NavigationError } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof NavigationError) {
      // Display an error message or perform other tasks
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the final event...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scroll&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;Scroll&lt;/em&gt; event is emitted when the router navigates to a new route and the browser's scroll position needs to be reset. This event can be used to adjust the scroll position of the page or perform other tasks when the scroll position is reset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router, Scroll } from '@angular/router';

constructor(private router: Router) {
  this.router.events.subscribe(event =&amp;gt; {
    if (event instanceof Scroll) {
      // Adjust the scroll position or perform other tasks
    }
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also specify the scroll position for a route by using the scrollPosition option in the router.navigate() method. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.router.navigate(['/route'], { scrollPosition: [0, 0] });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will reset the scroll position to the top-left corner of the page when navigating to the /route route.&lt;/p&gt;

&lt;p&gt;A great way to see the navigation cycle is by subscribing to the Router service’s events observable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(private router: Router) {
  this.router.events.subscribe( (event: RouterEvent) =&amp;gt; console.log(event))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then also pass along an option of enableTracing: true in the router configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RouterModule.forRoot(ROUTES, {
  enableTracing: true
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the developer console, we can see the events emitted during navigation &lt;/p&gt;

&lt;p&gt;That's it! I hope this was helpful.&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
