Search code examples
javascriptobjectpropertiesrxjsobservers

How to observe multiple object property changes with rxjs?


I have an object that I want to observe for changes using rxjs. The object has multiple properties, and when any of them change, I want to be notified of WHICH one was changed and what is its new value. I've put together the following simplified version of my code but it doesn't work as desired: http://jsbin.com/sidukulowi/1/edit?js,console

const store = Rx.Observable.create(function(observer) {
  let state = { userActions: {
    window: {
      leftPanelWidth: 300,
      backgroundColor: 0xffffff,
    }
  }};

  observer.next(state);

  state = { userActions: {
    window: {
      leftPanelWidth: 250,
      backgroundColor: 0xffffff,
    }
  }};

  observer.next(state);

  state = { userActions: {
    window: {
      leftPanelWidth: 250,
      backgroundColor: 0xff00ff,
    }
  }};

  observer.next(state);
});


const subscribe = store
  .map( state => state.userActions.window )
  .distinctUntilChanged( ( a, b ) => {
    return a.leftPanelWidth === b.leftPanelWidth && a.backgroundColor === b.backgroundColor
  })
  .subscribe(val => console.dir(val));

When the above code runs, I correctly get updates telling me when something in the window object is changed, however I don't know how to figure out which property is the one that changed.

How would I modify this so that I can see that in the first change, it is the leftPanelWidth that changed from 300 to 250, and in the next change it was the backgroundColor that changed from 0xffffff to 0xff00ff ?


Solution

  • I'm only just starting to learn RxJX Observable,. So this might not be the simplest solution.

    But instead of distinctUntilChanged, you could use pairwise to check the previous & current values.

    eg.

    const store = Rx.Observable.create(function(observer) {
      let state = { userActions: {
        window: {
          leftPanelWidth: 300,
          backgroundColor: 0xffffff,
        }
      }};
      
      observer.next(state);
      
      state = { userActions: {
        window: {
          leftPanelWidth: 250,
          backgroundColor: 0xffffff,
        }
      }};
      
      observer.next(state);
      //lets add again to make sure it only when
      //changed..
      observer.next(state); 
      
      state = { userActions: {
        window: {
          leftPanelWidth: 250,
          backgroundColor: 0xff00ff,
        }
      }};
      
      observer.next(state);
      
    });
    
    
    const subscribe = store
      .map(a => a.userActions.window)
      .pairwise()
      .map(([a,b]) => 
        Object.entries(a)
          .filter(([k,v]) => b[k] !== v)
          .map(([k,v]) => ({
            property: k,
            old: a[k],
            new: b[k]
          }))
      )
      .filter(a => a.length)
      .subscribe(val => console.dir(val));
    
    console.log( '--------------Done--------------' );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.min.js"></script>