在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。
答案 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
)尝试相同操作时,