Angular - обработка routerLinkActive и queryParams

Обновление март 2021 г.

Команда Angular наконец объединила PR для этого, вы можете посмотреть https://github.com/angular/angular/pull/40303 для получения дополнительных сведений.

Чтобы использовать это, просто поместите

<div routerLinkActive="active-link" [routerLinkActiveOptions]="options">
</div>

Где options будет иметь форму IsActiveMatchOptions

export declare interface IsActiveMatchOptions {
    fragment: 'exact' | 'ignored';
    matrixParams: 'exact' | 'subset' | 'ignored';
    paths: 'exact' | 'subset';
    queryParams: 'exact' | 'subset' | 'ignored';
}

или просто примите логическое значение exact

{
   exact: boolean
}

Исходный вопрос

Я использую routerLink в Angular, как показано ниже

<li routerLinkActive="active">
    <a [routerLink]="['/view', 10]"                 
       [queryParams]="{'offset': 0, 'numberOfItems': 100}" 
       queryParamsHandling="merge">
        <div>View</div>
        <div><span class="badge" [innerHtml]="viewCount"></span></div>
    </a>
</li>

Итак, класс .active был добавлен в тег li, когда URL-адрес выглядит как

/view/10?offset=0&numberOfItems=100

Если URL-адрес был изменен на offset или numberOfItems на другое значение, класс .active будет удален, например.

/view/10?offset=0&numberOfItems=120

Я просмотрел angular docs и мне удалось заставить его работать, добавив еще один routerLink, но сделав его скрытым как показано ниже.

<li routerLinkActive="active">
    <a [routerLink]="['/view', 10]"                 
       [queryParams]="{'offset': 0, 'numberOfItems': 100}" 
       queryParamsHandling="merge">
        <div>View</div>
        <div><span class="badge" [innerHtml]="viewCount"></span></div>
    </a>
    <a [routerLink]="['/view', 10]" style="display:none;">                
        <div><span class="badge" [innerHtml]="viewCount"></span></div>
    </a>
</li>

Кажется, что описанный выше подход - это небольшая хитрость. Есть ли какая-либо конфигурация, которую я могу настроить для работы routerLinkActive, когда параметр маршрутизатора представлен с необязательным параметром запроса?


person trungk18    schedule 02.08.2017    source источник
comment
Просто изучаю варианты здесь: необходимо ли вводить значения параметров запроса (смещение = 0, items = 100) в тег <a>? Если это значения по умолчанию, не следует ли их устанавливать внутри самого целевого компонента? В этом случае вам понадобится только один <a>.   -  person Harry Ninh    schedule 02.08.2017
comment
С моей нынешней архитектурой это необходимо. Потому что я настраиваю 2 разных маршрута с одним и тем же компонентом и решаю. Один маршрут нуждается в этих параметрах, а другой - нет. Затем, когда вызывается resolve guard, я буду использовать параметры для получения данных соответственно.   -  person trungk18    schedule 02.08.2017
comment
Я только что проверил исходный код. Он сравнивает точный URL-адрес, поэтому нет конфигурации для отказа от параметров.   -  person Harry Ninh    schedule 02.08.2017


Ответы (3)


Я сталкиваюсь с той же проблемой, но похоже, что это задумано в соответствии с этим https://github.com/angular/angular/issues/13205

всавкин - создатель роутера.

person s-f    schedule 03.08.2018
comment
Спасибо за ссылку. Наше веб-приложение все еще сохранилось с небольшим взломом, о котором я упоминал в самом вопросе. Я могу изменить его на основе одного из ответов по вашей ссылке. - person trungk18; 03.08.2018
comment
да, некоторые ребята предоставили обходные пути, но я вернулся к дополнительным параметрам маршрутизатора - person s-f; 03.08.2018

Вы можете найти это полезным - расширить RouterLinkActive - элемент будет «выбран», если он содержит строку ...

import { Directive, Input, OnChanges, ElementRef, Renderer2, ChangeDetectorRef, SimpleChanges, Injector, AfterContentInit } from '@angular/core';
import { Router,RouterLinkActive, RouterLink, RouterLinkWithHref } from '@angular/router';


@Directive({
  selector: '[routerLinkActiveQS]',
  exportAs: 'routerLinkActiveQS'
})
export class RouterLinkQsactiveDirective extends RouterLinkActive implements OnChanges, AfterContentInit
 {

  @Input() 
  set routerLinkActiveQS(data: string[]|string) {
    (<any>this).routerLinkActive = data;
  }

  @Input() routerLinkActiveQSContains : string;

  constructor ( injector: Injector ) {
    super ( injector.get(Router),injector.get(ElementRef),injector.get(Renderer2),injector.get(ChangeDetectorRef));
    (<any>RouterLinkQsactiveDirective.prototype).isLinkActive = this.MyisLinkActive;
  }

  ngOnChanges(changes: SimpleChanges): void {
    super.ngOnChanges(changes); 
  }

  ngAfterContentInit(): void {
    super.ngAfterContentInit();
  }

  private MyisLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
    const result = (link: RouterLink | RouterLinkWithHref) => {
      let resultInsde = router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
      resultInsde = resultInsde || router.url.includes ( this.routerLinkActiveQSContains );
      return resultInsde;
    }
    return result;
  }

}
person DougS    schedule 03.03.2019
comment
Привет, Дуг, это работает для Angular 10? Я пробовал этот код в своем приложении, но он не работает. Похоже, что текущий RouterLinkActiveDirective не содержит метода с именем isLinkActive ... - person MatterOfFact; 09.10.2020
comment
@MatterOfFact - Я так не думаю, когда я обновился до 9, я думаю, что он сломался из-за несовместимой инъекции / подписи в базовом классе, я много лет баловался с переопределениями / расширениями маршрутизатора и обнаружил, что всякий раз, когда вы делаете что-то слишком низкое уровень обычно ломается в следующем выпуске .... - person DougS; 10.10.2020

Решение работает с Angular 11. Устанавливает ссылку как активную независимо от различных параметров запроса (сравниваются только сегменты / путь).

import * as _ from 'lodash';

import {
  AfterContentInit,
  ChangeDetectorRef,
  Directive,
  ElementRef, Input,
  OnChanges,
  OnDestroy,
  Optional,
  Renderer2, SimpleChanges
} from '@angular/core';
import { Router, RouterLink, RouterLinkActive, RouterLinkWithHref } from '@angular/router';

@Directive({
  selector: '[rcRouterLinkActive]',
  exportAs: 'rcRouterLinkActive',
})
export class RcRouterLinkActiveDirective extends RouterLinkActive  implements OnChanges, OnDestroy, AfterContentInit {
  @Input()
  set rcRouterLinkActive(data: string[]|string) {
    const classes = Array.isArray(data) ? data : data.split(' ');
    (<any>this).classes = classes.filter(c => !!c);
  }

  constructor(
    router: Router,
    element: ElementRef,
    renderer: Renderer2,
    cdr: ChangeDetectorRef,
    @Optional() link?: RouterLink,
    @Optional() linkWithHref?: RouterLinkWithHref
  ) {
    super(router, element, renderer, cdr, link, linkWithHref);
    (<any>RcRouterLinkActiveDirective).prototype.isLinkActive = this.isRcLinkActive;
  }

  /**
   * this method sets the link as active regardless of query params
   * @param router
   * @private
   */
  private isRcLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
    return (link: RouterLink|RouterLinkWithHref) =>{
      const linkPath = '/' + link.urlTree.root.children.primary.segments.join('/');

      return router.isActive(link.urlTree, this.routerLinkActiveOptions.exact) ||
        _.startsWith(router.url, linkPath);
    }
  }

  ngOnChanges(changes: SimpleChanges) {
    super.ngOnChanges(changes);
  }

  ngOnDestroy() {
    super.ngOnDestroy();
  }

  ngAfterContentInit() {
    super.ngAfterContentInit();
  }
}

Использование (работает как стандартный angular routerLinkActive):

<a ... rcRouterLinkActive="active" ...>Link text</a>
person botmachine    schedule 14.02.2021