Angular router link active nested menu

router link active angular 7
router link active angular 4
angular material routerlinkactive
angular router isactive
angular navbar routing
angular 6 dynamic menu example
routerlinkactive for multiple routes
active router links angular

I'm trying to make a nested menu with angular routes.

What I need is to apply class to a nested route if it's active and apply class to a parent component if its child is active.

How do I achieve this? For now I'm doing recursive menu building for ease of use when I need multilevel nesting.

component.html

<a (click)="toggleActive()" [class.active]="isActive" [routerLink]="menuItem.link" *ngIf="menuItem.link; else noLink">
  <i *ngIf="menuItem.faClass" class="fa fa-{{menuItem.faClass}}"></i>
  {{menuItem.name}} <span *ngIf="menuItem.children && menuItem.children.length > 0" class="fa fa-chevron-down"></span>
</a>

<ng-container *ngIf="menuItem.children && menuItem.children.length > 0">
  <ul class="nav child_menu" [class.active]="isActive" routerLinkActive="active"
      *ngFor="let item of menuItem.children">
    <li menu-item [menuItem]="item" (checkActive)="updateActiveState()"></li>
  </ul>
</ng-container>

<ng-template #noLink>
  <a (click)="toggleActive()" [class.active]="isActive">
    <i *ngIf="menuItem.faClass" class="fa fa-{{menuItem.faClass}}"></i>
    {{menuItem.name}} <span *ngIf="menuItem.children && menuItem.children.length > 0" class="fa fa-chevron-down"></span>
  </a>
</ng-template>

component.ts

@Component({
  selector: '[menu-item]',
  templateUrl: './menu-item.component.html',
  styleUrls: ['./menu-item.component.scss'],
  host: {
    '[class.active]': 'hostActive && isActive',
    '[class.active-sm]': 'hostActiveSm && isActive'
  }
})
export class MenuItemComponent implements OnInit, AfterViewInit, OnChanges {

  public menuSize;
  public isActive = false;

  @Input() menuItem: MenuItem;
  @Output() checkActive: EventEmitter<void> = new EventEmitter<void>();
  @ViewChild(MenuItemComponent) menuComponent: MenuItemComponent;

  private hostActive = true;
  private hostActiveSm = false;

  @HostBinding('class') hostClass = this.hostActive && this.isActive ? 'active' : this.hostActiveSm && this.isActive ? 'active-sm' : '';

  constructor(
    private router: Router,
    private uss: UiStateService,
  ) {
  }

  ngOnInit() {
    this.uss.menuSubject.subscribe(msg => {
      this.menuSize = msg;
      if (this.menuSize === MenuSizes.sm) {
        this.hostActive = false;
        this.hostActiveSm = true;
      } else {
        this.hostActive = true;
        this.hostActiveSm = false;
      }
      this.updateActiveState();
    });

    this.router.events.subscribe((e: Event) => {
      if (e instanceof NavigationEnd) {
        this.updateActiveState();
      }
    });
  }

  ngOnChanges() {
  }

  ngAfterViewInit() {
    this.updateActiveState();
  }

  public toggleActive(): void {
    this.isActive = !this.isActive;
    // if (this.menuComponent) {
    //   this.menuComponent.isActive = true;
    // }
  }

  private updateActiveState(): void {
    // reset previous state
    this.isActive = false;
    if (this.menuComponent) {
      this.menuComponent.isActive = false;
    }

    // Check state of item with no els
    const url = this.router.url;
    console.log('URL', url, 'Menu link', this.menuItem.link);
    console.log(url.match('/' + this.menuItem.link + '$/'));
    if (this.menuItem && this.menuItem.link && url.match('/' + this.menuItem.link + '$/')) {
      this.isActive = true;
      this.checkActive.emit();
    }

    if (this.menuComponent) {
      console.log('Menu component');
      console.log(this.menuComponent, this.menuComponent.menuItem.link);
      this.isActive = true;
    }
  }

}

Is there a way of knowing from a component whether its route is active? The trick is that I'm using [routerLink] and not a routerLink so that I can pass . as a link to the root page.

Update

The best I could recreate stackblitz Try to visit "Dasboard". It should add an "active" class to parent li. If you add it yourself you would see the applied class on it's element and a colored bar on the right.

Maybe you can try access ActivatedRoute in any component

import { Router, ActivatedRoute} from '@angular/router';    

 constructor(private router: Router, private activatedRoute:ActivatedRoute) {
    console.log(activatedRoute.snapshot.url)  // array of states
    console.log(activatedRoute.snapshot.url[0].path) 
 }

Hope that will help!

Allow routerLinkActive to work with descendant routerLinks · Issue , The routerLinkActive directive only appears to work for direct children of the directive. Nested menus are a very common use case, and having to write a Angular version: 2.0.0-rc.3; Browser: all; Language: Typescript.next  Initial Router Setup; Child Routes; Nested Child Routes; Auxiliary Routes; Nested Auxiliary Routes; This post is the second of a series on the Angular Router, here is the complete series: Angular Router Fundamentals: Child Routes, Auxiliary Routes, Master-Detail. Angular Router: A Complete Example (with Bootstrap) So without further ado, let's get started building our Angular navigation menu! The Menu System That We Are About To Build

StackBlitz

All of this functionality is built inside Angular's router module natively. This is the whole idea behind child routes. If a route is truly a parent component, it should be a parent in the routing. By doing this, you can simply check if the parent route is active instead of any of the routes arbitrarily assigned in the app component.

Additionally, this has the huge benefit of allowing dashboard to simply route to ['../sibling']

In my child routes specifically /home/home.routes, you will see a commented line that would enable the dashboard to automatically load if that was the desired behaviour.

You are already using routerLinkActive, in your dynamic menu-item, but to have the most straightforward approach, it should be on the item bound to the routerLink as outlined here.

The biggest issue you will likely encounter is that nested routerLink elements do not play nicely in the DOM as discussed in this question so you need to stop propagation.

app-component.html

<ul app-menu-item 
  class="nav side-menu"
  [menu]="menu">
</ul>

menu-item.html:

<li
  *ngFor="let item of menu"
  [routerLink]="item.link"
  routerLinkActive="active"
  (click)="stop($event)">

    {{item.name}}

    <ul app-menu-item
      *ngIf="item.children"
      class="nav side-menu"
      [menu]="item.children">
    </ul>
</li>

I will add, though it doesn't answer the title in your question, that this problem is most easily solved by using parent routes, and then setting up menu-item.html as follows:

<li *ngFor="let item of menu">
  <a [routerLink]="item.link" routerLinkActive="active">
    {{item.name}}
  </a>
  <ul class="nav side-menu"
  *ngIf="item.children"
  app-menu-item [menu]="item.children">
  </ul>
</li>

and then using a sibling selector in your scss to show or hide the menu.

RouterLinkActive, Descriptionlink. This directive lets you add a CSS class to an element when the link's route becomes active. Consider the following example:. Angular 8 custom nested menu working example I have done with custom code and I am showing limited menus and if you want more then you can add according to your requirement. For styling, I used bootstrap and font awesome cdns.

I've managed to workaround it. StackBlitz

Mainly it's achieved by using setTimeOut without a time in navigateEnd event so that I can check the state of isActive and get the value(if there is no setTimeout the value is gotten "from the past" meaning it's not updated when it's taken). It works in a bit tricky way but it works

Angular router link active nested menu - angular - html, I'm trying to make a nested menu with angular routes. What I need is to apply class to a nested route if it's active and apply class to a parent component if its child  Using this directive, we can toggle CSS classes for active Router Links based on the current RouterState. The main use case of this directive is to highlight which route is currently active. The main use case of this directive is to highlight which route is currently active.

Angular Router: A Complete Example (Bootstrap Navigation Menu), <ul class="nav navbar-nav" routerLinkActive="active"> Implementing a side navigation menu using a Nested Auxiliary Route. In order to  The router link directive always treats the provided input as a delta to the current url. For instance, if the current url is /user/(box//aux:team) . Then the following link <a [ routerLink ]="['/user/jim']">Jim</a> will generate the link /user/(jim//aux:team) .

Active routerLinkActive with multiple routes · Frontpills, The routerLinkActive directive lets you add a class to an element when the If we navigate to the /about page, Angular will remove the first active class, This is extraordinarily helpful when building common headers and navigation menus. routerLinkActive directive also detects child nested routerLink  Angular is a platform for building mobile and desktop web applications. Join the community of millions of developers who build compelling user interfaces with Angular. Help Angular by taking a 1 minute survey !

Nested Routes • Angular, We can nest routes, this means that for a given URL we can render a tree of components. A list of tracks for that artist by additionally passing in entity=song :. @brandonroberts If we have nested routes as illustrated, below code has dropdown menu items Generated Reports and Adhoc Reports under Reports tab. when user clicks on Reports tabs bootstrap dropdown will show and we can click on Adhoc or Generated Reports, how can we make Reports tab as active I mean hightlight it, even though we are actually clicking on Adhoc reports submenu.

Comments
  • Can you please create stackblitz example?
  • It's too complicated cause it requires almost full aplication to recreate
  • @yurzui updated the question
  • Please reread the end of my question. I may pass . since I'm using [routerLink] and I don't want to match this case manually since it could change over time.
  • Sorry I got it wrong but you said very clear 'Is there a way of knowing from a component whether its route is active?'. Im answering that. Good luck
  • The idea is that "Home" that contains dashboard should have class active. In real application it's a kinda accordion and I need to expand an item when it's descendants are active. (by applying the class to the item).
  • In my example, the styling was off, but it does have the active class. Take a look here. It may be more clear.
  • you've done it in a wrong way. I've told about recursion meanwhile in your example it's absent. That means that you've got only 2 levels of menu and if I pass with dashboard children it won't render them.
  • Updated answer and stackblitz given your feedback.
  • nice work but still not the same :) Your implementation now lacks a such thing as linkless item, because it's a strange thing when a parent item has link, meanwhile it's just a grouping item. Since, we cannot do a conditional route link (which exists only if a value present [routerLink]="" refers to a home page) we do have a problem with propagating this routerActive state to a parent that doesn't have a link itself.