我想从根/单例服务更新 URL 的一个查询参数。此服务的职责是在 URL 中保留一些共享状态以进行深度链接。
问题是例如ActiveRoute 不起作用,因为此服务未绑定到路由并且始终返回“/”。同样使用 Angular router.url 在服务构建时不起作用,这个路由 url 也是“/”。
我找到了一种方法(见下文)来执行此操作,但它看起来 very hacky,我正在寻找一种更简洁的方法来做到这一点。
@Injectable({
providedIn: 'root',
})
export class MyService implements OnDestroy {
(...)
private updateUrlOnDataChange() {
this.dataChanges.pipe(untilDestroyed(this)).subscribe((data) => {
const segments = this.router.parseUrl(this.location.path()).root.children['primary']
?.segments;
const pathFragments = (segments || []).map((segment) => segment.path);
const params = this.router.parseUrl(this.location.path()).queryParams;
params['data'] = JSON.stringify(data);
this.router.navigate(pathFragments, {
queryParams: params,
});
});
}
}
所以其实我想做的只是
this.router.navigate([], {
queryParams: params,
queryParamsHandling: 'merge'
});
这是行不通的。从绑定到该服务不是的叶路由段的组件执行它时,它会起作用。
也许这只是因为缺乏对 Router API 的了解,但我在文档中找不到与我的问题相关的任何信息。
[编辑]
看来,我遇到了这个问题。如果在应用程序完全初始化(包括路由器)后更新查询参数,则下面提出的解决方案有效。当粘贴更新内部状态然后再次更新 URL 参数的深层链接时,情况还不是这样。在那个时间点,路由器/ActivatedRoute 还没有用浏览器的实际 URL 初始化,只是返回“/”,没有查询参数。
在链接的 git hub 问题中,提出了几个解决方案。
[编辑 2]
建议的解决方案有效除非您在根服务的构造函数中尝试更新查询参数。那个时候路由器还没有初始化。
所以我向 QueryParamsService 引入了一个可观察对象,其他服务可以使用它来确定路由器何时初始化:
export class QueryParamsService {
public initialized$: Observable<void>;
private readonly initializedSubject: ReplaySubject<void> = new ReplaySubject<void>(1);
private routerInitialized = false;
constructor(private readonly router: Router, private readonly route: ActivatedRoute) {
this.initialized$ = this.initializedSubject.asObservable();
this.router.events
.pipe(
filter((event: RouterEvent) => !!event && event instanceof NavigationEnd),
take(1)
)
.subscribe(() => {
this.routerInitialized = true;
this.initializedSubject.next(undefined);
});
}
(...)
我还使用
this.routerInitialized
在初始化完成之前修改查询参数时抛出错误。
import { Injectable } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class QueryParamService {
constructor(private route: ActivatedRoute, private router: Router) {}
public addQueryParam(paramName: string, paramValue: string): void {
const queryParams = { ...this.route.snapshot.queryParams };
queryParams[paramName] = paramValue;
this.router.navigate([], { queryParams });
}
public modifyQueryParam(paramName: string, paramValue: string): void {
const queryParams = { ...this.route.snapshot.queryParams };
if (queryParams[paramName]) {
queryParams[paramName] = paramValue;
this.router.navigate([], { queryParams });
}
}
}