I would like to use Semantic UI in my Angular2 application. The problem is that I can't find a router setting that changes the default name of "router-link-active" class. I need it to be called just "active" to make menus display properly.
As I understand, such setting doesn't exist. I've seen it in Vue.JS so I expect it to be there too. Is it a good idea to ask developers to fix this?
So. We need to write a custom directive that adds "active" class to all DOM elements with "router-link-active" class, but I've got some problems here too.
There is a similar question but the answer is too complicated and didn't work for me. So I have read some documentation and decided to do something better like this:
commons.ts:
@Directive({
selector: '.router-link-active',
host: {'[class.active]': 'trueConst'} //just 'true' could also work I think...
})
export class ActiveRouterLinkClass {
trueConst: boolean = true; //...if 'true' works we don't need this
}
Then I've imported ActiveRouterLinkClass into my main.component.ts and added it to the component's directives list. Unfortunately, now I have this error: "EXCEPTION: Unexpected directive value 'undefined' on the View of component 'Main'". Please, explain what I did wrong!
Angular doesn't apply directives or components to selectors that are dynamically applied. If the class .router-link-active
is added to a link is dynamic and therefore won't work.
What you can do instead is using a more generic selector like [routerLink]
and than read whether .router-link-active
is set using an @Input()
and set the desired class using host binding.
@Directive({
selector: '[routerLink]')
export class RouterLinkReplaceClass {
// add class `my-active` when `myActiveClass` is `true`
@HostBinding('class.my-active')
// read `router-link-active` class state
@Input('class.router-link-active')
myActiveClass: bool = false;
}
Plunker example
See also In Angular 2 how do I assign a custom class to an active router link?
update
because myActiveClass
isn't updated when the router-link-active
class is added/removed I modified the directive to get the information about the active route the same way as 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) {
// we need to update the link whenever a route changes to account for aux routes
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;
}
}
Based on Günter Zöchbauer's answer, after breaking changes in angular2 rc1, this is working for me now.
import { Directive, Input, HostBinding, OnInit } from '@angular/core';
import { Router, RouteSegment, UrlTree } from '@angular/router';
@Directive({
selector: '[routerLink]'
})
export class RouterActiveClass 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 isRouteActive(): boolean {
return this.currentUrl ? this.router.urlTree.contains(this.currentUrl) : null;
}
ngOnInit() {
this.updateCurrentUrl();
}
}