RxJS distinctUntilChanged - object mapping

I have a stream of objects, and I need to compare if the current object is not the same as the previous one, in which case it emits a new value. I found that the differUntilChanged statement should do exactly what I want, but for some reason it never emits a value other than the first one. If I delete the differUntilChanged value, it returns fine.

My code is:

export class SettingsPage { static get parameters() { return [[NavController], [UserProvider]]; } constructor(nav, user) { this.nav = nav; this._user = user; this.typeChangeStream = new Subject(); this.notifications = {}; } ngOnInit() { this.typeChangeStream .map(x => {console.log('value on way to distinct', x); return x;}) .distinctUntilChanged(x => JSON.stringify(x)) .subscribe(settings => { console.log('typeChangeStream', settings); this._user.setNotificationSettings(settings); }); } toggleType() { this.typeChangeStream.next({ "sound": true, "vibrate": false, "badge": false, "types": { "newDeals": true, "nearDeals": true, "tematicDeals": false, "infoWarnings": false, "expireDeals": true } }); } emitDifferent() { this.typeChangeStream.next({ "sound": false, "vibrate": false, "badge": false, "types": { "newDeals": false, "nearDeals": false, "tematicDeals": false, "infoWarnings": false, "expireDeals": false } }); } } 
+18
angular reactive-programming rxjs
source share
6 answers

I had the same problem and fixed using JSON.stringify to compare objects:

.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))

Dirty but working code.

+23
source share

I’ll finally find out where the problem is. The problem was in the RxJS version, in V4 and earlier - the order is different from V5.

RxJS 4:

distinctUntilChanged = function (keyFn, comparer)

RxJS 5:

distinctUntilChanged = function (comparer, keyFn)

In every document today you can find the order of the V4 parameters, beware of this!

+21
source share

In any case, if your application has lodash, you can simply use the lodash function isEqual() , which performs a deep comparison and perfectly matches the signature isEqual() distinctUntilChanged() :

 .distinctUntilChanged(isEqual), 

Or, if you have _ availability (which is no longer recommended these days):

 .distinctUntilChanged(_.isEqual), 
+7
source share

Mehdi's solution, although quick, will not work if the order is not followed. Using one of the libraries with deep or fast deep equality :

 .distinctUntilChanged((a, b) => deepEqual(a, b)) 
+1
source share

If you change the value mutably, none of the other answers will work. If you need to work with volatile data structures, you can use distinctUntilChangedImmutable , which copies the deep previous value, and if the comparison function is not passed, it will argue that the previous and current values ​​are deeply equal to each other (not === statement).

0
source share

From RxJS v6 + there is a greatUntilKeyChanged

https://www.learnrxjs.io/operators/filtering/distinctuntilkeychanged.html

 const source$ = from([ { name: 'Brian' }, { name: 'Joe' }, { name: 'Joe' }, { name: 'Sue' } ]); source$ // custom compare based on name property .pipe(distinctUntilKeyChanged('name')) // output: { name: 'Brian }, { name: 'Joe' }, { name: 'Sue' } .subscribe(console.log); 
0
source share

All Articles