What you actually want to do, is to manage your application's (global) state.
Option 1: Using nested components
In case you have a parent- and a child-component, just use EventEmitters. Could look like:
nav.ts
export enum MenuName = {
Menu1 = 'Menu 1',
Menu2 = 'Menu 2'
}
export const navItems: INavData[] = [
{
name: MenuItem.Menu1,
...
},
];
child.component.ts
@Output() badgeChange = new EventEmitter<{menuName: MenuName, value: string}>();
private updateBadge(menuName: MenuName, value: string) {
this.badgeChange.next({menuName, value});
}
and listen to the change in your parents HTML: <app-child (badeChange)="onBadgeChanged($event)"></app-child>
and in TS:
onBadgeChanged(change: {menuName: MenuName, value: string}): void {
// find menu item by `change.menuName`
// update it's badge value
}
Option 2: Use a service for global state
If your global state is simple, you can also use a service for your state:
nav-service.ts
export class NavService {
navData$ = new BehaviourSubject<INavData[]>([
{
name: "Menu 1",
...
},
]);
updateBadge(menuItemName: string, value: string): void {
// find menu item by `menuItemName` in `this.navData$.value`
const menuItem = ...;
if (menuItem) {
menuItem.badge.text = value;
this.navData$.next([...this.navData$.value]); // emit new nav data
}
}
}
In this case, your menu-component would listen to changes of this.navService.navData$
and the component or service which updates the data, uses this.navService.updateBadge(...)
to tell everyone that the value has changed.
Option 3: Use a state management library
If your state is more complex than just a menu, I would suggest to use a state library such as NgRx, NgXs or Akita. Follow the links to learn more about them, I use NgRx for my projects. The idea is similar to using an own service for state, except the entire state is kept in one state-object and more sophisticated concepts are introduces by these libraries.