Rxjs observing object updates and changes

27,794

Solution 1

If you want only the nested object changes:

var source = rx.Observable.from(a).flatMap(function(item) {
  return rx.Observable.ofObjectChanges(item);
});

If you also want changes like a[0] = a[1]:

var source = rx.Observable.merge(
  rx.Observable.ofArrayChanges(a),
  rx.Observable.from(a).flatMap(function(item) {
    return rx.Observable.ofObjectChanges(item);
  })
);

The flatMap or selectMany (they are the same function) will allow you to iterate over a value and execute a function that returns an Observable. The values from all these Observables are "flattened" onto a new stream that is returned.

http://reactivex.io/documentation/operators/flatmap.html

Solution 2

Perhaps something like this by merging two Observables (one for the array and the other observing the elements of the array):

var a = [
  {a:1,b:2},
  {a:2,b:5}
];


var source1 = Rx.Observable.ofArrayChanges(a).map(function(x) {
  return JSON.stringify(x);
});

var source2 = Rx.Observable
.fromArray(a.map(function(o, i) { return [o, i]; }))
.flatMap(function(oi) {
  return Rx.Observable.ofObjectChanges(oi[0])
  .map(function(x) {
    var y = {
      type: x.type,
      object: x.object,
      name: x.name,
      oldValue: x.oldValue,
      arrayIndex: oi[1] // pass the index of the member that changed
    };
    return JSON.stringify(y);
  });
})

source = source1.merge(source2)

var subscription = source.subscribe(
  function (x) {log(x);},
  function (err) {log(err);},
  function () {log('Completed');}
);


a[0] = a[1]
a[1]['b'] = 7

Thanks to @electrichead here we're not using concatMap because the sources that we made by ofObjectChanges and ofArrayChanges never complete.

Share:
27,794
WeeniehuahuaXD
Author by

WeeniehuahuaXD

Full stack software engineer. Love X-Platform stuff but JS kinda became my life lol

Updated on July 09, 2022

Comments

  • WeeniehuahuaXD
    WeeniehuahuaXD almost 2 years

    I am currently trying to observe any changes to a given object including all of it's elements.

    The following code only fires when an object[x] is updates, but not if individually updating object[x]'s elements such as object[x][y]

    <script>
      var elem = document.getElementById("test1");
    
    var log = function(x) {
        elem.innerHTML += x + "<br/><br/><br/>";
    };
    
    var a = [{a:1,b:2},
             {a:2,b:5}
           ];
    
    
    var source = Rx.Observable
    .ofObjectChanges(a)
    .map(function(x) {
        return JSON.stringify(x);
    });
    
    
    var subscription = source.subscribe(
        function (x) {log(x);},
        function (err) {log(err);},
        function () {log('Completed');}
    );
    
    a[0] = a[1];
    </script>
    

    This code runs and fires correctly.

    however. if I instead to this

    a[0]['a'] = 3;
    

    Then nothing happens.

    EDIT

    A better way to phrase this, how can I observe changes from an array of objects?

  • Antonio
    Antonio about 8 years
    to make it work I needed to change rx into Rx and add the map function at the end of the merge. Cool!
  • serkan
    serkan over 7 years
    'rx.Observable.ofObjectChanges' depriciated.
  • akaRem
    akaRem over 7 years
    Checked out in Safari & Chrome. Snippet provided by link appears to be broken.
  • Marek M.
    Marek M. over 6 years
    Yep, seeing this method as depreciated, I would really like to see how to observe object changes in RxJS 5...