Modifying the standard name of the "router-link-active" class through the creation of a personalized directive to include a different class

Trying to incorporate Semantic UI into my Angular2 application has presented a challenge. I am unable to locate a router setting that allows me to change the default name of the "router-link-active" class to simply "active," which is crucial for proper menu display.

It seems that such a customization option does not currently exist, unlike in Vue.JS where it is available. Should I consider reaching out to developers to address this issue?

The workaround involves creating a custom directive that automatically adds the "active" class to all DOM elements with the "router-link-active" class, but I have encountered some obstacles along the way.

I came across a similar question, however, the suggested solution proved overly complex and ineffective in my case. After reviewing documentation, I devised an alternative approach as follows:

commons.ts:

@Directive({
    selector: '.router-link-active',
    host: {'[class.active]': 'trueConst'} //simply using 'true' may also suffice
})
export class ActiveRouterLinkClass {
    trueConst: boolean = true; //if 'true' works, this line could be omitted
}

Subsequently, I imported ActiveRouterLinkClass into my main.component.ts and included it in the component's list of directives. However, this resulted in an error message stating: "EXCEPTION: Unexpected directive value 'undefined' on the View of component 'Main'". Any insights on what went wrong would be greatly appreciated!

Answer №1

When using Angular, directives or components are not applied to dynamically added selectors. In the case where a dynamic class like .router-link-active is applied to a link, it will not work as expected.

One alternative approach is to use a more generic selector such as [routerLink] and then check for the presence of .router-link-active using an @Input(), setting the desired class with host binding.

@Directive({
  selector: '[routerLink]')
export class RouterLinkReplaceClass {
  // Add class `my-active` when `myActiveClass` is `true`
  @HostBinding('class.my-active') 

  // Read state of `router-link-active` class
  @Input('class.router-link-active') 

  myActiveClass: bool = false;
}

Take a look at a Plunker example here

For more information, visit this Stack Overflow discussion

Update:

Since myActiveClass does not update when the router-link-active class is added or removed, I have made modifications to the directive to obtain information about the active route in a similar manner to the RouterLink directive:

import {ROUTER_DIRECTIVES, RouteConfig, Router, Instruction} from 'angular2/router';

@Directive({
  selector: '[routerLink]'
})
export class RouterLinkReplaceClass {

  //@Input('class.router-link-active')
  // myActiveClass: boolean = false;
  private _navigationInstruction: Instruction;
  @Input('routerLink')
  private _routeParams: any[];

  constructor(private _router: Router) {
    // Update the link whenever a route changes
    this._router.subscribe((_) => this._updateLink());
  }

  private _updateLink(): void {
    this._navigationInstruction = this._router.generate(this._routeParams);
  }

  @HostBinding('class.my-active')
  get isRouteActive(): boolean {
    return this._navigationInstruction ? this._router.isRouteActive(this._navigationInstruction) : null;
  }
}

Answer №2

After reviewing Günter Zöchbauer's solution, I have successfully implemented it following the angular2 rc1 breaking changes.

import { Directive, Input, HostBinding, OnInit } from '@angular/core';
import { Router, RouteSegment, UrlTree } from '@angular/router';

@Directive({
    selector: '[routerLink]'
})
export class ActiveRouterClass implements OnInit {
    private currentUrl: UrlTree;
    @Input('routerLink') private routerLink: any[];

    constructor(private routeSegment: RouteSegment, private router: Router) {
        this.router.changes.subscribe(() => this.updateCurrentUrl());
    }

    private updateCurrentUrl(): void {
        this.currentUrl = this.router.createUrlTree(this.routerLink, this.routeSegment);
    }

    @HostBinding('class.active')
    get isLinkActive(): boolean {
        return this.currentUrl ? this.router.urlTree.contains(this.currentUrl) : null;
    }

    ngOnInit() {
        this.updateCurrentUrl();
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble with your Typescript *.ts files?

Having trouble understanding why the command tsc *.ts isn't functioning correctly. The error message TS6053: File '*.ts' not found keeps appearing. Any suggestions on how to compile all the .ts files within a directory? Thank you! ...

A click function within a cell should not initiate a click function within a row

Within an Angular Material table, each row displays a name and a link in separate cells. My goal is to trigger the rowFunction when any part of the row is clicked, and to trigger the linkFunction specifically when the link itself is clicked. The current a ...

Display different icons in an Angular application based on the value received from an API in real

My goal was to create a dynamic form that displays icons for the fields I have created. Here is a snapshot of my UI screen showing the field explorer with the list coming from an API. https://i.sstatic.net/4Ye9G.png I need to place an icon in front of ea ...

Issues with implementing PrimeNG Data List component in Angular 4

I'm encountering an issue with my data list in primeng as I try to run the app: Can't bind to 'value' since it isn't a known property of 'p-dataList' The HTML file looks like this: <p-dataList [value]="cars"> ...

Steps for transferring an uploaded .CSV file to a Web service

I'm exploring the process of sending a file uploaded from the UI (angular) to a .NET web service in order for it to parse a CSV file and create a list of objects. My current understanding of the logic flow is: File upload ---> Web Service (parse ...

Setting a property with a generic type array: Tips and tricks

Currently, I am working on implementing a select component that can accept an array of any type. However, I am facing some challenges in defining the generic and where to specify it. My project involves using <script setup> with TypeScript. Here is ...

Can semicircles be created using Leaflet and Angular together?

In my angular application, I am utilizing maps with the help of ngx-leaflet library along with openstreet maps. Lately, there is a need to incorporate semicircles into the map visualization. Although I have already integrated the Leaflet-semicircle exten ...

How to dynamically load a component in Angular 7 with the click of a button

I am looking to implement a feature where clicking on a row in my table will load a specific component. In order to test this functionality, I have created a simple alert that pops up when a row is clicked displaying the message THIS ROW HAS CLICKED. This ...

A TypeScript object with user-defined keys

I have a question about utilizing TypeScript records with a custom Type as keys. Essentially, I have a specific type (a limited set of strings) that I want to use as keys for my record. My goal is to start with an empty initialization of this record. type ...

The expression "routerlink" in Angular 9 is not recognized,

Currently, I am in the process of developing an Angular 9 application and have encountered two challenging issues. Firstly, as I navigate through the routes using the navbar, I notice an error message in the console stating "Syntax error, unrecognized exp ...

Encountered a problem when trying to show a PDF viewer within a Bootstrap modal

Trying to preview a PDF using a bootstrap modal, but encountering an error: Error: Unable to initialize viewer. TypeError: Cannot read property 'div' of undefined When the modal is called, the PDF does not display initially. However, if the s ...

Guide on creating a zodiac validator that specifically handles properties with inferred types of number or undefined

There are some predefined definitions for an API (with types generated using protocol buffers). I prefer not to modify these. One of the types, which we'll refer to as SomeInterfaceOutOfMyControl, includes a property that is a union type of undefined ...

Retrieving the selected value from a <select> element when it changes

Check out the code snippet below: The HTML part is located in component.html: <select id="select" (change)="selectInputUpdate(this.value)"> <option *ngFor="let option of filteredOptions" value="{{option .Id}}" class="select-option">< ...

Tailored directory layout for Angular CLI

While setting up my new Angular project with Angular CLI, I am facing a challenge. My desired folder structure is as follows: -- src -- components -- app -- students -- faculty -- admin -- common -- search ...

Switch branches to projects without node_modules installed

Is there a better way to checkout a project that had node_modules in .gitignore? I have 2 computers and currently follow the following steps: Commit the project from computer 1 to GitHub Create a new angular project with the same name and folder structur ...

Issue a tslint warning when mockResolvedValueOnce is used with async/await

While working with the request-promise module, everything seems to be functioning correctly except for a warning from tslint. Below is my unit test: import * as request from 'request-promise'; jest.mock('request-promise', () => { ...

Executing a function in the Angular 5 template based on the results of an observable leads to multiple function calls

Custom HTML Template <div *ngFor="let element of convertObjectToArray(observerable_value)"> {{element.name}} </div> Custom Component convertObjectToArray(obj) { const arr = Object.values(obj); return arr; } Seeking Solution I ...

The icon for caret down in FontAwesome is not displaying when using ngClass

I am experiencing an issue where only the fontawesome caret up is displayed when sorting a field, but the fontawesome caret down is not showing. I have provided the code snippet below. HTML <th (click)="sort('ref')">Ref {{reverse}} & ...

Discover the pixel width of a Bootstrap grid row or container using JavaScript

How can I calculate the width of a Bootstrap grid row or container in pixels using JavaScript? I am working with Aurelia for my JavaScript project, but I'm open to solutions in standard JS (no jQuery, please). Looking at the Bootstrap documentation, ...

Unable to locate the type definition file for 'jquery'

After updating my NuGet packages, I encountered an issue where I can no longer compile due to an error related to the bootstrap definition file not being able to find the jquery definition file within my project. Prior to the update, the directory structu ...