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

时间:2019-01-19 14:34:27

标签: angular angular-routing ngrx angular-router ngrx-router-store

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

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

当前页面作为查询参数import java.lang.reflect.Field; import java.util.AbstractMap; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; import javax.persistence.EntityManager; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport; import org.springframework.data.jpa.repository.support.JpaRepositoryFactory; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments; import org.springframework.util.Assert; public class InterfaceBasedJpaRepositoryFactory extends JpaRepositoryFactory { private final Map<? extends Class<?>, ? extends Class<?>> interfaceToEntityClassMap; private final EntityManager entityManager; private boolean allowNonInterfaceTypes = true; public InterfaceBasedJpaRepositoryFactory(EntityManager entityManager) { super(entityManager); this.entityManager = entityManager; this.interfaceToEntityClassMap = entityManager.getMetamodel().getEntities().stream() .flatMap(et -> Arrays.stream(et.getJavaType().getInterfaces()) .map(it -> new AbstractMap.SimpleImmutableEntry<>(it, et.getJavaType()))) .collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (possibleDuplicateInterface, v) -> v)); } public InterfaceBasedJpaRepositoryFactory(EntityManager entityManager, boolean paramAllowNonInterfaceTypes) { this(entityManager); this.allowNonInterfaceTypes = paramAllowNonInterfaceTypes; } @Override @SuppressWarnings("unchecked") public <T, ID> JpaEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) { JpaEntityInformation<T, ID> ret = null; // Interface entities if (this.allowNonInterfaceTypes == false) { Assert.isTrue(domainClass.isInterface(), "You are using interface based jpa repository support. The entity type used in DAO should be an interface"); Class<T> domainInterface = domainClass; Class<?> entityClass = this.interfaceToEntityClassMap.get(domainInterface); Assert.notNull(entityClass, String.format("Entity class for a interface %s not found!", domainInterface)); ret = (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getEntityInformation(entityClass, entityManager); }else { // Class entities ret = super.getEntityInformation(domainClass); } return ret; } @Override protected RepositoryMetadata getRepositoryMetadata(Class<?> repositoryInterface) { RepositoryMetadata ret = super.getRepositoryMetadata(repositoryInterface); Class<?> clazz = ret.getClass(); try { Field f = clazz.getDeclaredField("domainType"); boolean isAccessible = f.isAccessible(); f.setAccessible(true); Class<?> actualValue = (Class<?>) f.get(ret); Class<?> newValue = this.interfaceToEntityClassMap.get(actualValue); f.set(ret, newValue); f.setAccessible(isAccessible); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } return ret; } } 存储在URL中,并且PaginationComponent从user/:userId/agent?page=0获取当前页面。但是,如果用户访问URL state.router.state.queryParams.page,则user/:userId/agent返回undefined。

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

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

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

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

3 个答案:

答案 0 :(得分:1)

针对您的问题:

  

可以将没有查询参数的路由重定向到有查询参数的路由吗?

我认为这行不通,因为?查询中的分隔符不属于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,或者更可取的是,创建一个常规页面列表方法进行检查,并在没有页面的情况下将其添加到请求中。 This answer显示了如何实现添加参数的示例。

替代3 -您可以将该页面用作路径的一部分,并根据需要进行解决/更改以生成请求。

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

答案 1 :(得分:1)

  

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

要使查询参数和状态同步,您需要一种效果,该效果可以捕获导致应用程序页面更改的所有操作。在活动内部,您将拥有类似的内容:

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

然后有一个meta reducer来更新页面重新加载时查询参数的状态:

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中。因此,即使您在该路由获取其初始数据之后转到新的路由(组件),效果也会触发更新查询参数的事件。

您可能想要查看有关角度应用程序中状态管理的惊人article

答案 2 :(得分:0)

对我来说,这适用于根路径:

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

但是,当使用命名的参数(例如您的:userId)尝试相同操作时,