My Application has the following app-routing.module.ts
:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { PageNotFoundComponent } from './core/page-not-found/page-not-found.component';
const routes: Routes = [
{ path: '', redirectTo: 'forms', pathMatch: 'full' },
{ path: 'forms', loadChildren : () => import('./pages/forms/forms.module').then(m => m.FormsModule) },
{ path: 'admin', loadChildren : () => import('./pages/admin/admin.module').then(m => m.AdminModule) },
{ path: '**', component: PageNotFoundComponent }
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
As you can see, I have two of what I call "products", they are "forms" and "admin", and they are acessed by the url /forms and /admin respectively.
The app.component.html
is as follows:
<navbar></navbar>
<div class="container">
<ngx-spinner
bdColor = "rgba(51, 51, 51, 0.6)"
size = "large"
color = "white"
type = "ball-running-dots">
<p style="font-size: 20px; color: white">Loading...</p>
</ngx-spinner>
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
As you can see, I have the component "navbar", tagged as <navbar></navbar>
. The thing is that, the content of this navbar will vary based on the product that the user are in. To make things more clear, let's take a look in the navbar.component.html
:
<default-navbar *ngIf="currentProduct == 'forms'"></default-navbar>
<div *ngIf="currentProduct != 'forms'">
lalalallala
</div>
And also in the navbar.component.ts
:
import { OnInit, OnDestroy, Component } from '@angular/core';
import { Subscription } from '../../../../../node_modules/rxjs';
import { ProductEnum } from '../../../shared/models/enums/product-enum';
import { ProductContainer } from '../../../shared/containers/product-container';
@Component({
selector: 'navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit, OnDestroy
{
public currentProduct:ProductEnum;
private subscription = Subscription.EMPTY;
constructor(private _productContainer:ProductContainer)
{
}
ngOnInit(): void
{
this.currentProduct = this._productContainer.getCurrentProduct();
this.initializeSubscribers();
}
ngOnDestroy(): void
{
this.subscription.unsubscribe();
}
private initializeSubscribers():void
{
this.subscription.add(this._productContainer.getChangeCurrentProductSubject().subscribe(_newCurrentProduct => {
this.currentProduct = _newCurrentProduct;
}));
}
}
So the navbar content will vary depending on the currentProduct
property. And this variable will be updated by the subject property that exists on a injectable service that I called ProductContainer
(horrible name by the way, I know).
Here is the ProductContainer
(product-container.ts
) code:
import { Injectable } from '@angular/core';
import { Subject } from '../../../../node_modules/rxjs';
import { ProductEnum } from '../models/enums/product-enum';
@Injectable({
providedIn: 'root',
})
export class ProductContainer
{
private changeCurrentProductSubject: Subject<ProductEnum> = new Subject<ProductEnum>();
private currentProduct: ProductEnum = ProductEnum.Forms;
public setCurrentProduct(_newCurrentProduct:ProductEnum):void
{
this.currentProduct = _newCurrentProduct;
this.changeCurrentProductSubject.next(this.currentProduct);
}
public getCurrentProduct():ProductEnum
{
return this.currentProduct;
}
public getChangeCurrentProductSubject():Subject<ProductEnum>
{
return this.changeCurrentProductSubject;
}
}
So if we go back to the app-routing.module.ts
, we can see the when the \admin url is acessed, the AdminModule
is loaded. Here is the AdminModule
code:
import { CommonModule } from '@angular/common';
import { SharedModule } from '../../shared/shared.module';
import { NgModule } from '@angular/core';
import { AdminRoutingModule } from './admin-routing.module';
import { AdminHomeModule } from './admin-home/admin-home.module';
import { CoreModule } from '../../core/core.module';
import { ProductContainer } from '../../shared/containers/product-container';
import { ProductEnum } from '../../shared/models/enums/product-enum';
import { Router, RouterModule } from '@angular/router';
@NgModule({
declarations: [],
imports: [
CommonModule,
SharedModule,
AdminRoutingModule,
AdminHomeModule,
CoreModule,
RouterModule
]
})
export class AdminModule
{
constructor(private _productContainer:ProductContainer, private router: Router)
{
this._productContainer.setCurrentProduct(ProductEnum.Admin);
}
}
So, when the \admin url acessed, it will set the current product to Admin, so the navbar will have knowledge that the product has been updated.
But the issue is very simple, the subscribe inside the navbar is not being triggered.
(edit: Part of the bug was also caused by the use of private subscription = Subscription.EMPTY;
, it stated working when I replaced with private subscription = new Subscription();
)