在我的 Angular 应用程序中,我有一个包含一组过滤器的页面,这些过滤器可以切换然后立即提交。
我使用一个基本服务构建了它,它有一个过滤器对象(过滤器名称指向过滤器值)。localFilters
该服务的数据结构在组件(,如果用户没有提交就退出,它不会更新全局服务(localFilters
退出时清除)。
然而,我一直在让使用这些数据的组件与使用它的服务和其他组件保持同步时遇到问题,所以我决定尝试 NgRx,因为我理解这种基于 observable 的模式对于 Angular 来说更为典型,并且具有之前在一些 React 项目中使用过 Redux。
但是,由于两个原因,我在设置它时遇到了重大问题:
我之前在服务中使用的模式涉及
localFilters
在组件挂载时根据全局过滤器对象的状态设置对象。这些localFilters
将用于确定页面上过滤器的起始状态,并在提交时全局设置。然而,使用 NgRx 使用的 observable 模式,没有filters
要复制的对象——只有一个 observable,因此我不知道如何初始化该localFilters
对象。因此,我不知道如何从这个全局对象中设置各种过滤器组件的默认状态。更基本的是,我不知道如何在模板中显示过滤器值(如果我无法将其数据复制到本地对象,则尤其必要)。NgRx 上的基本入门文档展示了如何使用管道将数值合并到模板中
async
,但是因为我的数据是对象形式,并且我想传递该对象的值,所以这种技术不起作用。我已经根据上面的链接尝试了以下尝试——filters$ | async
(显示[Object object]
)、filters$.someKey | async
(不显示任何内容)和(filters$ | async).someKey
(同样不显示任何内容)。
基本上,最大的问题是我如何访问存储在 NgRx 状态中的对象的快照,以初始化此过滤器组件的本地状态,并在模板中呈现来自对象的值(或传递这些值)。
还是我应该遵循更好的模式?(好的例子很难找到,将不胜感激)。
下面是我的一堆相关代码。
动作文件:
import { Action } from '@ngrx/store';
export enum ActionTypes {
SetFilter = 'SetFilter',
SetFilters = 'SetFilters',
ClearFilters = 'ClearFilters',
}
export class SetFilter implements Action {
readonly type = ActionTypes.SetFilter;
constructor(public name: string, public value: any) {}
}
export class SetFilters implements Action {
readonly type = ActionTypes.SetFilters;
constructor(public filters: object) {}
}
export class ClearFilters implements Action {
readonly type = ActionTypes.ClearFilters;
}
export type ActionsUnion = SetFilter | SetFilters | ClearFilters;
减速器文件:
import * as FilterActions from './actions';
export interface State {
filters: object
};
export const initialState: State = {
filters: { wassup: 'true' } // testing initial state with some nonsense
};
export function reducer(state = initialState, action: FilterActions.ActionsUnion) {
switch (action.type) {
case FilterActions.ActionTypes.SetFilter: {
return { ...state, [action.name]: action.value };
}
case FilterActions.ActionTypes.SetFilters: {
return { ...state, ...action.filters };
}
case FilterActions.ActionTypes.ClearFilters: {
return {};
}
default: return state;
}
}
缩写 AppModule:
import { StoreModule } from '@ngrx/store';
import { reducer } from './ngrx/filters/reducer';
@NgModule({
declarations: [...],
imports: [
...,
StoreModule.forRoot({ filters: reducer })
],
...
})
以及相关 component.ts 文件的缩写版本:
@Component({
selector: 'app-base-filter',
templateUrl: './base-filter.component.html',
styleUrls: ['./base-filter.component.scss']
})
export class BaseFilterComponent implements OnInit {
/** Object with selected indices for given filter keys. */
selectedIndices: any = {};
/** Duplicate all filters locally, to save on submit and clear on cancel */
localFilters: any = {};
filters$: Observable<object>;
constructor(private store: Store<{ filters: object }>) {
this.filters$ = store.pipe(select('filters'));
this.initLocalFilters();
}
ngOnInit() {}
// This worked with the old filtersService model
// But is obviously broken here, because I haven't been able to init
// localFilters correctly.
initLocalFilters () {
this.localFilters = {};
// Fill pre-selections from filter service
['this', 'is a list of', 'names of filters with', 'an array of options']
.forEach((arrayKey) => {
// The selected indices are used in the template to pass to child
// components and determine selected content.
this.selectedIndices[arrayKey] = (this.localFilters[arrayKey] || [])
.map(t => this[arrayKey].indexOf(t));
});
}
});
顺便说一句,我在上面的组件构造函数中尝试了以下一些内容:
// Doesn't throw an error, but doesn't enter the callback
this.store.select(data => { console.log(data) });
// Doesn't throw an error, but filter is undefined inside the loop
this.filters$ = store.pipe(select('filters'));
this.filters$.forEach(filter => { console.log(filter) });
不确定是否可以循环遍历过滤器的键/值。