在阅读并尝试了到目前为止的所有内容以将我的 AdditionalCollectionStates 更新为我的 EntityCollection 之后(基于文档中的一些信息,this SO Question,this other SO Question,another SO question和来自github存储库的问题)我发现自己陷入了困境应该是一个相当普遍的任务,在使用ngrx之前完全没有问题:使用ngrx对存储的实体集合进行排序。搜索解决方案将我带回到我已经看过 5 次的相同的 10 个链接,大多数示例要么太基本,要么过时,要么根本不使用 ngrx/data,或者类似的问题根本没有答案。
环境:Angular 9.1.7,ngrx 9.1.2,macOS 10.14.6
目标
如排序和分页文档中所述,将own 添加和更新additionalCollectionState
到我的 EntityCollection 中。我没有从服务器获取sortQuery属性(sortField、sortDirection),而是在我的 GUI 中设置它并根据它们对集合进行排序。我知道 EntityMetadataMap 上存在设置,但它对我的方式不够灵活,我想在整个应用程序中对不同 MatTables 中的集合进行动态排序。每当 MatTable 中的排序顺序/字段发生更改时,都应更新此附加属性。sortComparer
到目前为止我所取得的成就:
如上所述的附加CollectionState 的ngrx/data 方式有效,我的集合使用我在EntityMetadataMap 中提供的数据进行初始化。但是,更新自定义集合属性并不能按照我从文档中理解的方式进行。由于我没有从服务器获取sortQuery属性,因此不会调用 ResultsHandler。
我通过两种方式解决了这个问题:a)使用 ngrx 和 ngrx/entity 方法和 b)通过尝试扩展自定义EntityCollectionReducer的 ngrx/data 方式
a) 我成功创建了自定义 Action 和自定义 Reducer 并更新了state 属性,但没有更新之前定义的集合属性。我的行动基本上是:
export const selectResourceSortQuery = createAction('[Resource] Get Last Sort Query', props<{ sortQuery: any }>());
它是从服务中调用的:
this.store.dispatch(selectResourceSortQuery({ sortQuery }));
并在减速器中处理:
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { Action, createReducer, on } from '@ngrx/store';
import * as ResourceActions from './resource.actions';
import { Resource } from 'src/app/sdk';
export interface State extends EntityState<Resource> {
// additional state property
sortQuery: any | null;
}
export const adapter: EntityAdapter<Resource> = createEntityAdapter<Resource>();
export const initialState: State = adapter.getInitialState({
// additional entity state properties
sortQuery: {
sortDirection: 'asc',
sortField: 'product'
},
});
export const resourceReducer = createReducer(
initialState,
on(ResourceActions.selectResourceSortQuery, (state, { sortQuery }) => {
console.log(`REDUCER called`);
return { ...state, sortQuery };
}),
);
export function reducer(state: State | undefined, action: Action) {
return resourceReducer(state, action);
}
reducer 在 reducers/index.ts 中导出:
import {
ActionReducer,
ActionReducerMap,
createFeatureSelector,
createSelector,
MetaReducer
} from '@ngrx/store';
import { environment } from 'src/environments/environment';
import * as fromResourceReducers from 'src/app/store/entities/resource/resource.reducer';
export interface State {
}
export const reducers: ActionReducerMap<State> = {
resourceSort: fromResourceReducers.reducer
};
export const metaReducers: MetaReducer<State>[] = !environment.production ? [] : [];
在 app.module 中设置为:
StoreModule.forRoot(reducers, {
metaReducers: [
ngrxEntityRelationshipReducer //ignore this
],
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true
}
}),
这将创建一个带有sortQuery属性的resourceSort集合,如该屏幕截图所示:并根据更改后的 sortQuery 属性对其进行更新。但是,我更喜欢在 Resource entityCache 集合中使用已经初始化的 sortQuery 属性(是的,我也尝试将其添加到entityCache功能中并忽略它): StoreModule.forFeature('entityCache', reducers)
b) 因此,另一种方法是在 app.module 中使用 EntityCollectionReducerRegistry:
import { resourceReducer } from './store/entities/resource/resource.reducer';
// does not work: resourceReducer is of type ActionReducer<State, Action> and the same as posted above (with the added handling of the sortQuery property), and apparently what this function expects
entityCollectionReducerRegistry.registerReducer('Resources', resourceReducer);
// this does work, but just creates the basic default entity collection reducer without my custom sortQuery handling
entityCollectionReducerRegistry.registerReducer('Resources', entityCollectionReducerFactory.create('resources'))
从文档:
Entity Reducer 是存储实体缓存中所有实体集合的主 reducer。该库没有命名实体减速器类型。相反,它依赖于 EntityCacheReducerFactory.create() 方法来生成该 reducer,它是一个 NgRx ActionReducer<EntityCache, EntityAction>。
我有一种感觉,使用 b) 方法我可能走在正确的轨道上,但是我被缺乏如何处理这个问题的文档和示例所困扰 - 有没有人可以帮助我?
如果需要更多详细信息,我很乐意提供,如果有不清楚的地方,因为英语不是我的母语,我很乐意澄清,如有必要,请尝试提供一个简化的 stackblitz 示例。谢谢!