How to add active class to link which has fragmment in angular?

Viewed 1335

Angular version is 7 and I want to add active class to the link clicked. Here the link is old school navigation(routing trough ID).

My HTML code follows as below:

<div class="sidenav-container">
  <div class="list">
    <mat-list role="list">
      <mat-list-item role="listitem"
        ><a
          routerLink="./"
          fragment="report"
          >1. Report</a
        ></mat-list-item
      >
      <mat-list-item role="listitem"
        ><a
          routerLink="./"
          fragment="profile"
          >2. Profile</a
        >
      </mat-list-item>
    </mat-list>
  </div>
</div>

And my css file looks as below:

.active {
  color: green;
  font-weight: 900;
}
2 Answers

In angular we add routerLinkActive directive to add css class(say active class) to the link. This directive will add active class to the particular link when it's active. But fragments won't be counted for this scenario.

To rectify this issue, If you're using router version 7.2.4, We can fix easily with the following code [routerLinkActiveOptions]="{ exact: true }"

Then the original code will look like the below one:

<div class="sidenav-container">
  <div class="list">
    <mat-list role="list">
      <mat-list-item role="listitem"
        ><a
          routerLink="./"
          fragment="report"
          routerLinkActive="active"
          [routerLinkActiveOptions]="{ exact: true }"
          >1. Report</a
        ></mat-list-item
      >
      <mat-list-item role="listitem"
        ><a
          routerLink="./"
          routerLinkActive="active"
          fragment="profile"
          [routerLinkActiveOptions]="{ exact: true }"
          >2. Profile</a
        >
      </mat-list-item>
    </mat-list>
  </div>
</div>

If the router version is below 7.2.4, we've to use the below approach to fix this issue.

Inject ActivatedRoute the in componnet

code will look as below:

import { ActivatedRoute } from '@angular/router';
import { share } from 'rxjs/operators';

activeFragment = this.route.fragment.pipe(share());
constructor(public route: ActivatedRoute) {}

Then we've to add the class as below to the HTML template.

[class.active]="(activeFragment | async) === 'report'"

The full code in HTML will look as the below:

<div class="sidenav-container">
  <div class="list">
    <mat-list role="list">
      <mat-list-item role="listitem"
        ><a
          routerLink="./"
          fragment="report"
          [class.active]="(activeFragment | async) === 'report'"
          >1. Report</a
        ></mat-list-item
      >
      <mat-list-item role="listitem"
        ><a
          routerLink="./"
          fragment="profile"
          [class.active]="(activeFragment | async) === 'profile'"
          >2. Profile</a
        >
      </mat-list-item>
    </mat-list>
  </div>
</div>

A solution here could be to keep the selected item and put class input in the anchor like this:

<mat-list-item role="listitem"
    ><a
      routerLink="./"
      (click)="selectedAnchor = 'report'"
      [class]="selectedAnchor === 'report' ? 'active' : ''"
      fragment="report"
      >1. Report</a
    ></mat-list-item
  >
  <mat-list-item role="listitem"
    ><a
      routerLink="./"
      (click)="selectedAnchor = 'profile'"
      [class]="selectedAnchor === 'profile' ? 'active' : ''"
      fragment="profile"
      >2. Profile</a
    >
  </mat-list-item>

And in the component.ts just create a property called selectedAnchor = '';

Related