如何从代码更新 Observable / BehaviorSubject?
How to update Observable / BehaviorSubject from code?
我需要更新可观察对象的属性。我设法使它工作,但我真的不喜欢我是如何做到的。
next(filter$: BehaviorSubject<GridCollectionFilter>, collection: GridCollectionModel<any>) {
let filter = filter$.value;
if (!filter.page) {
filter.page = 1;
}
filter.page++;
if (filter.page > collection.pageCount) {
filter.page = collection.pageCount;
}
this.updateFilter(filter$);
}
first(filter$: BehaviorSubject<GridCollectionFilter>) {
filter$.value.page = 1;
this.updateFilter(filter$);
}
last(filter$: BehaviorSubject<GridCollectionFilter>, collection: GridCollectionModel<any>) {
filter$.value.page = collection.pageCount;
this.updateFilter(filter$);
}
updateFilter(filter$: BehaviorSubject<GridCollectionFilter>, filter?: GridCollectionFilter) {
filter$.next(_.clone(filter || filter$.value));
}
在这种情况下,是否有更优雅的方法来更新 filter$
值对象?
我真的不喜欢每次我只想通过代码更新被观察对象的一些属性时,通过 filter$.next(_.clone(filter$.value))
将可观察对象的克隆喂给自己的想法。我正在使用 _.clone()
来破坏引用(否则 rxjs distinctUntilChanged()
不会因为明显的原因而触发)。
是否有某种 rxjs 扩展可以缩短我正在做的事情?我在想一些类似于 filter$.commitValueChanges()
的东西,它会在内部做 filter$.next(_.clone(filter$.value))
.
我对 observables 还很陌生,所以我不确定我一开始是否以完全错误的方式思考这个问题。我知道当我想触发更改侦听器时我应该提交新状态。我不确定您是否应该直接修改 filter$.value ?或者你通常应该有两个对象 - filter
(过滤器)和 filter$
(过滤器可观察到的)然后绝对不要直接改变 filter$
而是简单地提交 filter
.next()
每次 filter
发生变化?但这似乎是多余的,因为我们现在有两个对象,一个是我们通过应用程序更改的,必须通过附加各种事件处理程序来手动处理,所有这些只是为了能够更新另一个 - filter$
.这对我来说似乎太过分了。
谢谢。
要从您的代码中删除 _clone(),您应该使用 distinctUntilKeyChanged()。它将检查对象中的任何键是否被更改。
但更好的方法是:
filter$: BehaviorSubject<GridCollectionFilter>;
collection: GridCollectionModel<any>;
currentFilter: GridCollectionFilter;
ngOnInit() {
this.filter$.subscribe(filter => {
this.currentFilter = filter;
// Here for example invoke rest api with filter to change collection
})
}
next() {
if (!this.currentFilter.page) {
this.currentFilter.page;
}
this.currentFilter.page++;
if (this.currentFilter.page > this.collection.pageCount) {
this.currentFilter.page = collection.pageCount;
}
this.filter$.next(this.currentFilter);
}
first() {
this.currentFilter.page = 1;
this.filter$.next(this.currentFilter);
}
last(filter$: BehaviorSubject<GridCollectionFilter>, collection: GridCollectionModel<any>) {
this.currentFilter.page = collection.pageCount;
this.filter$.next(this.currentFilter);
}
如果您唯一的问题是需要克隆对象,也许以下提示之一会对您有所帮助:
distinctUntilChanged
运算符默认比较对象标识。但是,它需要一个可选的 compare
函数,您可以使用该函数来实现您想要的任何比较登录。
.distinctUntilChanged((a, b) => a.page === b.page)
您还可以使用它来比较具有相同属性的两个不同实例
.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
如果您不介意只创建浅拷贝,您可以使用其中之一:
Object.assign({}, filter)
或者这个:
{ ...filter }
这两个都是浅拷贝。
如果你需要深拷贝并且你不担心性能(看起来你有非常小的对象)你可以使用JSON
:
JSON.parse(JSON.stringify(filter))
这样你就不需要任何第 3 方库了。
无论如何,我完全理解你的问题 - 因为我正在努力解决完全相同的问题。我遇到了很多 Angular 变化检测问题,因为我直接修改了 subject 的值。现在我只是 _.cloneDeep 这个值,修改它然后用 .next() 将它反馈给主题。我也希望能为主题提供某种快捷方式来检测更改和发布新对象。暂时没有找到更好的解决办法
我需要更新可观察对象的属性。我设法使它工作,但我真的不喜欢我是如何做到的。
next(filter$: BehaviorSubject<GridCollectionFilter>, collection: GridCollectionModel<any>) {
let filter = filter$.value;
if (!filter.page) {
filter.page = 1;
}
filter.page++;
if (filter.page > collection.pageCount) {
filter.page = collection.pageCount;
}
this.updateFilter(filter$);
}
first(filter$: BehaviorSubject<GridCollectionFilter>) {
filter$.value.page = 1;
this.updateFilter(filter$);
}
last(filter$: BehaviorSubject<GridCollectionFilter>, collection: GridCollectionModel<any>) {
filter$.value.page = collection.pageCount;
this.updateFilter(filter$);
}
updateFilter(filter$: BehaviorSubject<GridCollectionFilter>, filter?: GridCollectionFilter) {
filter$.next(_.clone(filter || filter$.value));
}
在这种情况下,是否有更优雅的方法来更新 filter$
值对象?
我真的不喜欢每次我只想通过代码更新被观察对象的一些属性时,通过 filter$.next(_.clone(filter$.value))
将可观察对象的克隆喂给自己的想法。我正在使用 _.clone()
来破坏引用(否则 rxjs distinctUntilChanged()
不会因为明显的原因而触发)。
是否有某种 rxjs 扩展可以缩短我正在做的事情?我在想一些类似于 filter$.commitValueChanges()
的东西,它会在内部做 filter$.next(_.clone(filter$.value))
.
我对 observables 还很陌生,所以我不确定我一开始是否以完全错误的方式思考这个问题。我知道当我想触发更改侦听器时我应该提交新状态。我不确定您是否应该直接修改 filter$.value ?或者你通常应该有两个对象 - filter
(过滤器)和 filter$
(过滤器可观察到的)然后绝对不要直接改变 filter$
而是简单地提交 filter
.next()
每次 filter
发生变化?但这似乎是多余的,因为我们现在有两个对象,一个是我们通过应用程序更改的,必须通过附加各种事件处理程序来手动处理,所有这些只是为了能够更新另一个 - filter$
.这对我来说似乎太过分了。
谢谢。
要从您的代码中删除 _clone(),您应该使用 distinctUntilKeyChanged()。它将检查对象中的任何键是否被更改。
但更好的方法是:
filter$: BehaviorSubject<GridCollectionFilter>;
collection: GridCollectionModel<any>;
currentFilter: GridCollectionFilter;
ngOnInit() {
this.filter$.subscribe(filter => {
this.currentFilter = filter;
// Here for example invoke rest api with filter to change collection
})
}
next() {
if (!this.currentFilter.page) {
this.currentFilter.page;
}
this.currentFilter.page++;
if (this.currentFilter.page > this.collection.pageCount) {
this.currentFilter.page = collection.pageCount;
}
this.filter$.next(this.currentFilter);
}
first() {
this.currentFilter.page = 1;
this.filter$.next(this.currentFilter);
}
last(filter$: BehaviorSubject<GridCollectionFilter>, collection: GridCollectionModel<any>) {
this.currentFilter.page = collection.pageCount;
this.filter$.next(this.currentFilter);
}
如果您唯一的问题是需要克隆对象,也许以下提示之一会对您有所帮助:
distinctUntilChanged
运算符默认比较对象标识。但是,它需要一个可选的compare
函数,您可以使用该函数来实现您想要的任何比较登录。.distinctUntilChanged((a, b) => a.page === b.page)
您还可以使用它来比较具有相同属性的两个不同实例
.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
如果您不介意只创建浅拷贝,您可以使用其中之一:
Object.assign({}, filter)
或者这个:
{ ...filter }
这两个都是浅拷贝。
如果你需要深拷贝并且你不担心性能(看起来你有非常小的对象)你可以使用
JSON
:JSON.parse(JSON.stringify(filter))
这样你就不需要任何第 3 方库了。
无论如何,我完全理解你的问题 - 因为我正在努力解决完全相同的问题。我遇到了很多 Angular 变化检测问题,因为我直接修改了 subject 的值。现在我只是 _.cloneDeep 这个值,修改它然后用 .next() 将它反馈给主题。我也希望能为主题提供某种快捷方式来检测更改和发布新对象。暂时没有找到更好的解决办法