1

I am trying to wrap my head around the following issue. In the root-level app.component you have the following structure:

<div class="container"> <sidebar /> <menu-bar /> <div class="h-full w-full overflow-auto"> <main class="overflow-auto"> <router-outlet></router-outlet> </main> </div> </div> 

The menu-bar is only used in some of the routes and even might change. Therefore I don't want to provide a specific implementation, but more or less:

<div class="container"> <sidebar /> <ng-container *ngComponentOutlet="..." /> <div class="h-full w-full overflow-auto"> <main class="overflow-auto"> <router-outlet></router-outlet> </main> </div> </div> 

This outlet should be provided by a child component (indirectly). The child component depends on the current route.

ASP.NET Blazor for example has a concept called SectionOutlet which describes exactly what I want:

Here the app.component.html:

<div class="container"> <sidebar /> <section-outlet SectionName="menu-bar" /> <div class="h-full w-full overflow-auto"> <main class="overflow-auto"> <router-outlet></router-outlet> </main> </div> </div> 

Now when I have a process page, this page can then easily provide the content: process-page.component.html:

<section-content SectionName="menu-bar"> <my-real-menu/> </section> <OtherContent/> 

What is the idiomatic way of doing this in Angular?

1 Answer 1

1

Here are two ways to do this.

You can write a switchStatement or if statement that returns the correct menu component based on the route used.

private sub: Subscription = new Subscription(); menuComp: any; getMenu() { if(this.router.url.includes('/a-route') { this.menuComp = AMenuComponent } else if(this.router.url.includes('/b-route') { this.menuComp = BMenuComponent } } 

Then on router events navigation you trigger the logic to rerun.

ngOnInit() { this.sub.add( this.router.events.subscribe(value => { if(value instanceof NavigationEnd) this.getMenu(); }) ); } ngOnDestroy() { this.sub.unsubscribe(); } 

Finally use this property to dynamically create the menu.

<div class="container"> <sidebar /> <ng-container *ngComponentOutlet="menuComp" /> <div class="h-full w-full overflow-auto"> <main class="overflow-auto"> <router-outlet></router-outlet> </main> </div> </div> 

Another way is to use this same approach is to specify the component on the route data property.

export const routes: Routes = [ { path: 'a-route', component: AComponent, data: { menu: AMenuComponent } }, ]; 

The on the component root, subscribe to the data changes on the first child, then you can access this component and render using component outlet.

private sub: Subscription = new Subscription(); menuComp: any; ngOnInit() { this.sub.add( this.activatedRoute.firstChild.data.subscribe((data: any) => { this.menuComp = data.menu; ); } ngOnDestroy() { this.sub.unsubscribe(); } 

Same html for this as above method.

Sign up to request clarification or add additional context in comments.

2 Comments

Interesting approach. Thanks. This this.activatedRoute.firstChild.data will always give me an empty object. Is this due to the fact that app.component is outside of router-outlet?
Figured - it was loadChildren which was the problem

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.