Изменение имени по умолчанию класса "router-link-active" путем написания настраиваемой директивы, которая добавляет новый класс

Я хотел бы использовать Semantic UI в моем приложении Angular2. Проблема в том, что я не могу найти параметр маршрутизатора, который изменяет имя по умолчанию класса "router-link-active". Мне нужно, чтобы он назывался просто "активным", чтобы меню отображалось правильно.

Как я понимаю, такой настройки не существует. Я видел его в Vue.JS, поэтому я ожидаю, что он тоже будет там. Это хорошая идея попросить разработчиков исправить это?

Итак. Нам нужно написать настраиваемую директиву, которая добавляет "активный" класс ко всем элементам DOM с классом "router-link-active", но у меня также есть некоторые проблемы.

Существует аналогичный вопрос, но ответ слишком сложный и не работает для меня. Поэтому я прочитал некоторую документацию и решил сделать что-то лучше:

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
}

Затем я импортировал ActiveRouterLinkClass в свой main.component.ts и добавил его в список директив компонентов. К сожалению, теперь у меня есть эта ошибка: "ИСКЛЮЧЕНИЕ: Неожиданное значение директивы" undefined "в представлении компонента" Главная ". Пожалуйста, объясните, что я сделал неправильно!

Ответ 1

Angular не применяет директивы или компоненты для селекторов, которые динамически применяются. Если класс .router-link-active добавлен в ссылку, динамический и, следовательно, не будет работать.

Вместо этого вы можете использовать более общий селектор типа [routerLink], а затем прочитать, устанавливается ли .router-link-active с помощью @Input() и задает нужный класс с использованием привязки хоста.

@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;
}

Пример плунжера

См. также В Angular 2 как назначить настраиваемый класс для ссылки активного маршрутизатора?

Обновление

потому что myActiveClass не обновляется при добавлении/удалении класса router-link-active. Я изменил директиву, чтобы получить информацию об активном маршруте так же, как директива RouterLink:

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;
  }
}

Ответ 2

Основываясь на ответе Günter Zöchbauer, после нарушения изменений в angular2 rc1, это работает для меня сейчас.

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();
    }
}