- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前在 ngrx 项目中处理一个有点复杂(深层)的结构。它可以被认为是一个父对象数组,具有多个级别的子对象。它在服务器端被规范化/扁平化,我商店中的功能看起来像这样:
rootObjs: {
level1: {
byId: {
'lvl1_1': {id: 'lvl1_1', label: '[Lvl 1]: 1', ui_open: true, children: ['lvl2_1', 'lvl2_3']},
'lvl1_2': {id: 'lvl1_2', label: '[Lvl 1]: 2', ui_open: false, children: ['lvl2_2']}
},
allIds: [
'lvl1_1', 'lvl1_2'
]
},
level2: {
byId: {
'lvl2_1': {id: 'lvl2_1', label: '[Lvl 2]: 1', ui_open: false, children: ['lvl3_1', 'lvl3_2']},
'lvl2_2': {id: 'lvl2_1', label: '[Lvl 2]: 2', ui_open: true, children: ['lvl3_3']},
'lvl2_3': {id: 'lvl2_1', label: '[Lvl 2]: 3', ui_open: false, children: []}
},
allIds: [
'lvl2_1', 'lvl2_2', 'lvl2_3'
]
},
level3: {
byId: {
'lvl3_1': {id: 'lvl3_1', label: '[Lvl 3]: 1', ui_open: false,},
'lvl3_2': {id: 'lvl3_2', label: '[Lvl 3]: 2', ui_open: false,},
'lvl3_3': {id: 'lvl3_3', label: '[Lvl 3]: 3', ui_open: false,},
}
allIds: [
'lvl3_1', 'lvl3_2', 'lvl3_3'
]
}
}
现在我正在尝试编写我的选择器。我的问题是所有对象都需要同时显示在屏幕上,但是它们必须都可以单独编辑。因此,我正在尝试创建一个允许我单独选择每个组件的选择器 - 类似于:
export const rootObjFeature = createFeatureSelector<RootObj>('rootObjs');
export const selectLevel1 = (id: string) => createSelector(
rootObjFeature, (state: JobPlanner) => {
// Grab only the level2 children associated with selected level1
const lvl2 = state.level1.byId[id].children.map(key => state.level2.byId[key]);
// Grab only the level3 children of level2 associated with selected level1
const lvl3 = [].concat(
...state.lvl2.map( l2 => l2.children.map(key => state.level3.byId[key]));
);
return {
...state.level1.byId[id],
level2: lvl2,
level3: lvl3
};
}
);
然后在我的 Level1Component init 中,我做这样的事情:
export class Level1Component implements OnInit, OnDestroy {
@Input() id: string;
lvl1Sub: Subscription;
lvl1: Level1Model;
constructor(private store: Store<AppState>) { }
ngOnInit() {
this.lvl1Sub = this.store.select(selectLevel1(this.id)).subscribe(l1 => {
console.log('loading level 1: '+this.id);
this.lvl1 = l1;
});
}
ngOnDestroy() {
this.lvl1Sub.unsubscribe();
}
}
通过此设置,我可以将适当的 level2
和 level3
对象传递给它们自己的组件(这些子组件可以在其中打开、关闭、编辑等) .但是,由于我的选择器的方式,任何时候编辑任何 level1
、level2
或 level3
项目(例如- ui_open
为 lvl1_1
切换),调用每个 level1
组件的 lvl1Sub
方法。这是一个问题,因为我的 View 可能有数百个 level1 组件,但一次只能编辑一个。有没有一种方法可以设置一个选择器,使其仅在与单个 ID 关联的那些商店元素发生更改时才调用其订阅?
最佳答案
我也想过同样的事情。我认为问题在于您想要观察数组 (Level2s) 的过滤子集(特定 Level1 的子集)而不观察整个数组。然而,在我的理解中,整个数组(所有 Level2s)是 ngrx 公开用于观察的内容以及应用内存的内容。
我想到了三种解决方案。
首先是更改您的数据模型,以便给定级别的子项保存在它们自己的数组中。这实质上意味着将您的级别嵌套在您的状态中。如果你真的有一个树结构( child 只有一个 parent )而不是一个图形结构( child 有多个 parent )那么这可能有效。然而,保持你的状态平坦是最好的做法(https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape)。
第二种解决方案是在更精细的级别订阅。您可以将每个实体的 id 传递给其下方的组件,而不是创建其下具有嵌套对象的顶级对象,该组件将订阅其自己的状态片段。然后只有与该状态切片相关联的组件及其祖先才会收到通知。
第三种选择是做你自己的内存形式(默认:当接收到相同的参数时返回最后的结果)。使用 createSelector
的问题在于它只是查看数组的引用(例如 Level2 列表)并发现它发生了变化。您需要一种更深入的内存形式,比较您关心的切片内元素的引用,看看它们是否发生了变化。
穷人的版本是在投影结束时具体化模型之前设置您自己的独特过滤器。基本要点是,您将子项列表过滤为您想要的内容,应用成对运算符以便您可以知道上次获得的内容,然后过滤流以忽略当前对象内部对象引用的值和之前的 emit 是一样的。
下面是一些运行示例:
打开控制台看看发生了什么。它打印状态变化以及从状态到每个组件的变化。
对于#2,我完全 react 了,这增加了一点膨胀。在实践中,我通常不这样做。相反,我会将模型从 View 传递到需要它的函数中。
对于#3,我编写了一个名为distinctElements()
的自定义运算符,它类似于distinctUntilChanged()
运算符,但它比较的是数组中元素的引用,而不是数组本身。这是它的代码。
import { Observable } from 'rxjs/Observable';
import { startWith, pairwise, filter, map } from 'rxjs/operators';
export const distinctElements = () => <T>(source: Observable<T[]>) => {
return source.pipe(
startWith(<T[]>null),
pairwise(),
filter(([a, b]) => a == null || a.length !== b.length || a.some(x => !b.includes(x))),
map(([a, b]) => b)
)
};
关于angular - 非规范化 ngrx store- 设置选择器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49246694/
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!