如何在 Angular 7 中为 Route 设置默认查询参数?

How to set default query params for Route in Angular 7?

在我们的 Angular-7-Application 中,我们使用 @ngrx 和 @ngrx/router-store 将查询参数放入状态。

应用程序的一些组件是分页列表。我们将每个列表作为一个组件,每个列表中都包含分页组件。

当前页面作为查询参数存储在URL中:user/:userId/agent?page=0并且PaginationComponent从state.router.state.queryParams.page获取当前页面。但是,如果用户访问 URL user/:userId/agentqueryParams.page returns undefined.

我们可以通过在每个组件中使用 state.router.state.queryParams.page || 0 来解决这个问题,但我想知道是否有更简单的方法 - 可以将没有查询参数的路由重定向到具有查询参数的路由?

我尝试使用最明显的重定向:

{ path: 'user/:userId/agent', redirectTo: '/user/:userId/agent?page=0', pathMatch: 'full' },
{ path: 'user/:userId/agent?page=0', component: AgentListComponent },

但我得到 Error: Cannot match any routes. URL Segment: 'user/max/agent'

我发现的唯一功能请求是 this one 出现上述错误的地方。

具体针对您的问题:

can a Route without query params be redirect to a Route with query params?

我认为这行不通,因为 ?在查询中是一个分隔符,它不是 URL 查询字符串的一部分。

备选方案 1 - 由于您使用的是 ngrx,因此一种方法是使用自定义序列化程序。 The docs from the ngrx.io site 展示了一个通过序列化返回参数的例子。如果参数不存在,您可以在这里添加逻辑以将默认值添加到参数中。我会否认这可能不太理想,因为它会在每条路线上触发,但它可以使您的路线更简单。

import { Params, RouterStateSnapshot } from '@angular/router';
import { RouterStateSerializer } from '@ngrx/router-store';

export interface RouterStateUrl {
  url: string;
  params: Params;
  queryParams: Params;
}

export class CustomSerializer implements RouterStateSerializer<RouterStateUrl> {
  serialize(routerState: RouterStateSnapshot): RouterStateUrl {
    let route = routerState.root;

    while (route.firstChild) {
      route = route.firstChild;
    }

    const {
      url,
      root: { queryParams },
    } = routerState;
    const { params } = route;

    // Add here
    if (<insert url logic> && queryParams.page === undefined) {
        queryParams.page = 0;
    }

    // Only return an object including the URL, params and query params
    // instead of the entire snapshot
    return { url, params, queryParams };
  }
}

备选方案 2 - 您可以包装 HttpClient 或更优选地,创建一个通用的页面列表方法来检查这一点并在没有页面时将其添加到请求中。 显示了如何实现添加参数的示例。

备选方案 3 - 您可以将页面用作路径的一部分,并根据需要进行工作 arounds/changes 以生成您的请求。

{ path: 'user/:userId/agent', redirectTo: '/user/:userId/agent/0', pathMatch: 'full' },
{ path: 'user/:userId/agent/:page', component: AgentListComponent },

In our Angular-7-Application, we use @ngrx and @ngrx/router-store to get the query params into the state.

要使查询参数和状态同步,您需要一个效果来捕获导致应用程序页面更改的任何操作。在活动中,您将看到类似的内容:

@Effect({dispatch:false})
setRouteParams = this.actions$.pipe(
    ofType<ActionCausingPageChange>("action name"),
    tap( action =>{

        let a = { page: action.payload.page };
        // or in case it's not part of action payload, get it from store
        this.router.navigate(
            [], {
                relativeTo: this.route,
                queryParamsHandling: 'merge',
                queryParams: a
            });
        }
    )
);

然后使用元缩减器在页面重新加载时根据查询参数更新状态:

export function initStateFromQueryParams(
    reducer: ActionReducer<AppState>
): ActionReducer<AppState> {
    return function(state, action) {
        const newState = reducer(state, action);
        if ([INIT.toString(), UPDATE.toString()].includes(action.type)) {
            const urlParams = new URLSearchParams(window.location.search);
            return { ...newState, page: urlParams.get("page") };
        }
        return newState;
    };
}

这样您总能知道页码是否发生变化,它会因此反映在 url 中。因此,即使您在该路由获取其初始数据后转到新路由(组件),效果也会触发更新查询参数。

您可能想在 angular 应用程序

中查看关于状态管理的非凡 article

对我来说,这在根路径上有效:

{
  path: '',
  redirectTo: '/foo?bar=baz',
  pathMatch: 'full'
}

然而,当尝试使用命名参数(如您的 :userId)进行相同操作时,它不起作用