I have the need to update properties of an observable object. I managed to make it work, but I don't really like how I did it.
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));
}
Is there a more elegant way to update the filter$
value object in this case?
I really dislike the idea of dog-feeding the clone of the observable to itself by doing filter$.next(_.clone(filter$.value))
every time I simply want to update a few properties of the observed object through the code. I'm using _.clone()
to break the reference (otherwise rxjs distinctUntilChanged()
doesn't trigger for obvious reasons).
Is there some kind of rxjs extension which could shorten what I'm doing? I'm thinking of something along the lines of filter$.commitValueChanges()
which would internally do filter$.next(_.clone(filter$.value))
.
I'm pretty new to observables so I'm not sure if I'm thinking about this in a completely wrong way in the first place. I understand I'm supposed to commit the new state when I want to trigger the change listeners. What I'm not sure is whether you're ever supposed to modify the filter$.value directly? Or are you typically supposed to have two objects - filter
(the filter) and filter$
(observable of filter) and then absolutely never mutate the filter$
directly but simply submit filter
to .next()
every time a change on filter
occurs? But that would then seem redundant because we now have two objects, one which we're changing through the app and have to handle manually by attaching various event handlers and all that just to be able to update the other one - filter$
. That seems excessive and hacky to me.
Thnx.
To remove _clone() from your code you should use distinctUntilKeyChanged(). It will check if any key in object were change.
But the better aproach is:
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);
}