Angular:配置默认的 QueryParamsHandling

2024-01-16

我构建了一个 Angular 9 应用程序,并使用 @ngx-translate 添加了本地化功能。我已经配置了我的应用程序,以便它需要lang查询参数并相应地更改区域设置。

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
  constructor(private route: ActivatedRoute, private translateService: TranslateService) {
    this.translateService.setDefaultLang('en');
    this.route.queryParamMap.subscribe((params) => {
      let lang = params.get('lang');
      console.log('language', lang);
      if (lang !== null) {
        this.translateService.use(lang);
      }
    });
  }
}

然后我在侧边栏上添加了 3 个按钮来更改查询参数(并切换语言)

<div class="p-1 text-center">
  <a [routerLink]='[]' [queryParams]="{}">
    <app-flag [country]="'en'" [appHoverClass]="'brightness-250'"></app-flag>
  </a>
  <a [routerLink]='[]' [queryParams]="{'lang':'nl'}">
    <app-flag [country]="'nl'" [appHoverClass]="'brightness-250'"></app-flag>
  </a>
  <a [routerLink]='[]' [queryParams]="{'lang':'fr'}">
    <app-flag [country]="'fr'" [appHoverClass]="'brightness-250'"></app-flag>
  </a>
</div>

这工作正常。但是,当按下普通的 routerLink 或调用 router.navigate() 时,查询参数会再次丢失。

我不想装饰每一个routerLink在我的应用程序中[queryParamsHandling]="'preserve'"指令,因为这是一项乏味的工作和可怕的做法。该主题已经有一个活跃的 GitHub 问题,但 Angular 团队几乎没有致力于解决这个问题(已经 4 年了):https://github.com/angular/angular/issues/12664 https://github.com/angular/angular/issues/12664

有没有办法(任何方式)来获取查询参数(或只是lang导航时默认保留查询参数)?

我已经创建了一个ExtendedRouter在默认角度路由器的顶部

import { Router, QueryParamsHandling, NavigationExtras, UrlTree } from '@angular/router';

export class ExtendedRouter {
  constructor(private router: Router) {
  }

  private _defaultQueryParamsHandling: QueryParamsHandling = null;
  public get defaultQueryParamsHandling() {
    return this._defaultQueryParamsHandling;
  }
  public set defaultQueryParamsHandling(value: QueryParamsHandling) {
    this._defaultQueryParamsHandling = value;
  }

  public navigate(commands: any[], extras?: NavigationExtras) {
    return this.router.navigate(commands, {
      queryParamsHandling: extras.queryParamsHandling ?? this.defaultQueryParamsHandling ?? '',
      fragment: extras.fragment,
      preserveFragment: extras.preserveFragment,
      queryParams: extras.queryParams,
      relativeTo: extras.relativeTo,
      replaceUrl: extras.replaceUrl,
      skipLocationChange: extras.skipLocationChange
    });
  }

  public navigateByUrl(url: string | UrlTree, extras?: NavigationExtras) {
    return this.router.navigateByUrl(url, {
      queryParamsHandling: extras.queryParamsHandling ?? this.defaultQueryParamsHandling ?? '',
      fragment: extras.fragment,
      preserveFragment: extras.preserveFragment,
      queryParams: extras.queryParams,
      relativeTo: extras.relativeTo,
      replaceUrl: extras.replaceUrl,
      skipLocationChange: extras.skipLocationChange
    });
  }

  public createUrlTree(commands: any[], extras?: NavigationExtras) {
    return this.router.createUrlTree(commands, extras);
  }

  public serializeUrl(url: UrlTree) {
    return this.router.serializeUrl(url);
  }
}

但这不涉及[routerLink]指示。我也尝试过创建一个,但我需要的所有字段都限于private.

import { Directive, Renderer2, ElementRef, Attribute, Input } from '@angular/core';
import { RouterLink, Router, ActivatedRoute } from '@angular/router';
import { ExtendedRouter } from '../../helpers/extended-router';

@Directive({
  selector: '[extendedRouterLink]'
})
export class ExtendedRouterLinkDirective extends RouterLink {

  private router2: Router;
  private route2: ActivatedRoute;
  private commands2: any[] = [];
  constructor(router: Router, route: ActivatedRoute, @Attribute('tabindex') tabIndex: string, renderer: Renderer2, el: ElementRef<any>, private extendedRouter: ExtendedRouter) {
    super(router, route, tabIndex, renderer, el);
    this.router2 = router;
    this.route2 = route;
  }

  @Input()
  set extendedRouterLink(commands: any[] | string | null | undefined) {
    if (commands != null) {
      this.commands2 = Array.isArray(commands) ? commands : [commands];
    } else {
      this.commands2 = [];
    }
    super.commands = commands;
  }

  get urlTree() {
    return this.router2.createUrlTree(this.commands, {
      relativeTo: this.route2,
      queryParams: this.queryParams,
      fragment: this.fragment,
      queryParamsHandling: this.queryParamsHandling,
      preserveFragment: this.attrBoolValue(this.preserveFragment),
    });
  }

  private attrBoolValue = (s: any) => {
    return s === '' || !!s;
  }

}

任何人都知道如何解决这个问题而无需定义[queryParamsHandling]在各个[routerLink]?


这种方法有一个小问题:


@Directive({
  selector: 'a[routerLink]'
})
export class QueryParamsHandlingDirective extends RouterLinkWithHref {
  queryParamsHandling: QueryParamsHandling = 'merge';
}

问题是它延伸了RouterLinkWithHref,意味着<a routerLink="">将会有2 条指令(一个延伸另一个)连接到它。

And 这就是发生的事情 https://github.com/angular/angular/blob/master/packages/router/src/directives/router_link.ts#L203-L212 inside RouterLinkWithHref's click处理程序:

@HostListener('click')
onClick(): boolean {
  const extras = {
    skipLocationChange: attrBoolValue(this.skipLocationChange),
    replaceUrl: attrBoolValue(this.replaceUrl),
    state: this.state,
  };
  this.router.navigateByUrl(this.urlTree, extras);
  return true;
}

更重要的是它被发送到浏览器时的样子:

 RouterLinkWithHref.prototype.onClick = function (button, ctrlKey, metaKey, shiftKey) {
  if (button !== 0 || ctrlKey || metaKey || shiftKey) {
      return true;
  }
  if (typeof this.target === 'string' && this.target != '_self') {
      return true;
  }
  var extras = {
      skipLocationChange: attrBoolValue(this.skipLocationChange),
      replaceUrl: attrBoolValue(this.replaceUrl),
      state: this.state
  };
  this.router.navigateByUrl(this.urlTree, extras);
  return false;
};

这意味着当您单击<a>标签,该QueryParamsHandlingDirective.onClick将被调用,然后RouterLinkWithHref.onClick。但是由于RouterLinkWithHref.onClick被最后调用,它不会有queryParamsHandling set to merge.


解决方案是稍微修改自定义指令,使其不继承任何东西,但只是设置一个属性:

@Directive({
  selector: 'a[routerLink]'
})
export class QueryParamsHandlingDirective {
  constructor (routerLink: RouterLinkWithHref) {
    routerLink.queryParamsHandling = 'merge';
  }
}

堆栈闪电战 https://stackblitz.com/edit/angular-routing-preserve-queryparams-link-from-routing-c-eew3gj?file=src/app/directives/query-params-handling/query-params-handling.directive.ts.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular:配置默认的 QueryParamsHandling 的相关文章

随机推荐