Two components are visible - outlet1 and outlet2 at the same time

67 Views Asked by At

I can't understand the following behavior from angular routing. I have just two components HomeTestComponent and CustomerComponent. When I press Home button followed by Customer button both components are displayed - I would expect only one component to be visible at a time?

This is my app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerComponent } from './customer/customer.component';
import { HomeTestComponent } from './home-test/home-test.component';

const routes: Routes = [
  { path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) },
  { path: 'home', component: HomeTestComponent, outlet : "outlet2" }
];

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

This is my app.component.html

<h1>
  {{title}}
</h1>

<button type="button" [routerLink]="['customer', { outlets:{ outlet1: ['cust'] }} ]">Customer</button>
<button type="button" [routerLink]="['', { outlets:{ outlet2: ['home'] }}]">Home</button>

<router-outlet></router-outlet>

<div class="container">
<div class="row"><router-outlet name="outlet1"></router-outlet></div>
<div class="row"><router-outlet name="outlet2"></router-outlet></div>
</div>

and this is my customer-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerComponent } from './customer.component';

const routes: Routes = [{ path: 'cust', component: CustomerComponent, outlet: "outlet1" }];

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

Modifications: If I make my home-test module lazy loading, then only one component is shown at a time - why (I would have expected two to be consistent)?

home-test-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeTestComponent } from './home-test.component';

const routes: Routes = [{ path: 'hom', component: HomeTestComponent, outlet: "outlet2" }];

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

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerComponent } from './customer/customer.component';
import { HomeTestComponent } from './home-test/home-test.component';

const routes: Routes = [
  { path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) },
  { path: 'home', loadChildren: () => import('./home-test/home-test.module').then(m => m.HomeTestModule)}
];

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

app.component.html

<h1>
  {{title}}
</h1>

<button type="button" [routerLink]="['customer', { outlets:{ outlet1: ['cust'] }} ]">Customer</button>
<button type="button" [routerLink]="['home', { outlets:{ outlet2: ['hom'] }}]">Home</button>

<router-outlet></router-outlet>

<div class="container">
<div class="row"><router-outlet name="outlet1"></router-outlet></div>
<div class="row"><router-outlet name="outlet2"></router-outlet></div>
</div>
1

There are 1 best solutions below

6
Abru007 On

It seems like you're using named router outlets in your Angular application. Named router outlets allow you to have multiple outlets in your application's layout where different components can be loaded simultaneously.

Let's go through your code to understand why both components are displayed when you press the Home button followed by the Customer button.

  1. app-routing.module.ts:

You have defined two routes: '/customer' which lazy loads the CustomerModule. '/home' which loads the HomeTestComponent into the named outlet 'outlet2'. The 'home' route is using a named outlet 'outlet2'. app.component.html:

You have two buttons: 'Customer' and 'Home'. Clicking the 'Customer' button sets the route to '/customer' and activates the 'cust' route within the 'outlet1' named outlet. Clicking the 'Home' button sets the route to '/' and activates the 'home' route within the 'outlet2' named outlet. customer-routing.module.ts:

Defines the route '/cust' which loads the CustomerComponent into the named outlet 'outlet1'.

When you press the 'Customer' button followed by the 'Home' button, both components are displayed because Angular is rendering components into both named outlets simultaneously.

If you want only one component to be visible at a time, you should reconsider the use of named outlets. If you intend to have two separate areas where components can be loaded, then named outlets are the correct approach. Otherwise, if you want to display only one component at a time, you can use the primary router outlet without naming it.

Here's how you can modify your code to achieve that:

  1. Remove the named outlets from your routes and template.
  2. Define your routes without named outlets.
  3. Use the primary router outlet in your template.

Here's a modified version of your code:

app-routing.module.ts:

    const routes: Routes = [
  { path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) },
  { path: 'home', component: HomeTestComponent }
];

app.component.html:

<h1>{{title}}</h1>

<button type="button" [routerLink]="['customer']">Customer</button>
<button type="button" [routerLink]="['home']">Home</button>

<router-outlet></router-outlet>

With these modifications, only one component will be displayed at a time, depending on which button you click.

If you make home-test module lazy loading

When you make the HomeTestModule lazy-loaded, you are changing how Angular loads and manages the components within that module. Lazy loading means that the module and its components are loaded only when they are needed, typically when the corresponding route is activated.

In your original setup, HomeTestComponent was eagerly loaded as it was directly imported into the AppRoutingModule. With lazy loading, HomeTestComponent is no longer eagerly loaded. It is loaded only when the 'home' route is activated.

Here's how the behavior changes when you make HomeTestModule lazy-loaded:

  1. Initially, when the application loads, only the AppComponent is loaded because it's not tied to any route.
  2. When you click the 'Customer' button, the CustomerModule is loaded into the named outlet 'outlet1', and the CustomerComponent is rendered.
  3. When you click the 'Home' button, the HomeTestModule is loaded into the named outlet 'outlet2', and the HomeTestComponent is rendered, replacing whatever component was previously rendered in that outlet. Since named outlets are independent, the CustomerComponent remains visible in 'outlet1'.

Because lazy loading delays the loading of the HomeTestModule until the 'home' route is activated, you see the behavior where only one component is displayed at a time. This behavior is consistent with Angular's lazy loading mechanism, which loads modules and their components dynamically based on the route configuration.