Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to watch object changes with rxjs 5

I would like to watch over an object, so all the subscribers will be informed for any changes of it.

I saw it already been asked before, yet the answer is irrelevant since RXjs verion 5 do not include the ofObjectChanges in it's API anymore.

I've looked at some "hacks" like creating an observer which return a function:

let myObservable =  new Observable((observer) => {
  return (data) => {
    observer.next(data)
  }
}) 
//...
myObservable.subscribe()('someData')

However, I'm sure there is more elegant way of doing it. Any Ideas?

like image 625
yuval.bl Avatar asked Jun 05 '17 12:06

yuval.bl


People also ask

What are observers in RxJS?

The following is an example of a typical Observer object: To use the Observer, provide it to the subscribe of an Observable: Observers are just objects with three callbacks, one for each type of notification that an Observable may deliver. Observers in RxJS may also be partial.

How do I take values from an observable in RxJS?

RxJS also offers takeWhile (), which allows you to take values until some boolean test holds true. We can write the above stream with takeWhile () like this: Aside from the fact that they work on Observables, not arrays, these functions are almost identical the familiar list operations.

What does update () do in RxJS?

update () takes care of updating the UI to reflect what we got from the server. Handling debounce, retry, and “distinct until changed” logic in an imperative, callback-based style is valid, but it can be both brittle and complicated. The takeaway is that programming with RxJS allows for:

What is reactive programming with RxJS?

Note: This article presupposes familiarity with the basics of RxJS, as presented in the article Introduction to Functional Reactive Programming with RxJS. Reactive programming is a programming paradigm that treats streams of data, called Observables, as its basic units of programming.


2 Answers

The ES6 way of observing an object is with Proxies. You create a Proxy that wraps the original object and do your work on it. You can use it to create something similar to Observable.ofObjectChanges. Here a partial implementation (only set. You'd need to implement the other traps):

Observable.ofProxyChanges = (target) => {
  let subject = new Subject
  let proxy = new Proxy(target, {
    set(target, key, val) {
      let oldValue = target[key]
      target[key] = val
      subject.next({
        type: oldValue === undefined ? "add" : "change",
        object: target,
        name: key,
        oldValue: oldValue
      })
    }
  })
  return [proxy, subject.asObservable()]
}

let [obj, objChange$] = Observable.ofProxyChanges({})
objChange$.subscribe(console.log)

obj.bar = 1 // logs { type: "add", name: "bar", object: { bar: 1 } }
obj.foo = 2 // logs { type: "add", name: "foo", object: { bar: 1, foo: 2 } }
obj.foo = 3 // logs { type: "change", name: "foo", object: { bar: 1, foo: 3 }, oldValue: 2 }
like image 60
Federico Galassi Avatar answered Oct 21 '22 14:10

Federico Galassi


I would suggest using something similar to redux approach, when changes to the object can be made in predefined way:

function factory(reducerByType, initialState) {
  const action$ = new Rx.Subject();
  const state$ = action$
    .startWith(initialState)
    .scan((state, action) => {
      if (reducerByType.hasOwnProperty(action.type)) {
        return reducerByType[action.type](state, action);
      }
      
      return state;
    })
    .distinctUntilChanged();
  
  
  return {
    action$,
    state$,
    dispatch: action => action$.next(action)
  }
}

const {state$, dispatch} = factory({
  ADD: (state, action) =>  state + action.number,
  SUBTRACT: (state, action) =>  state - action.number,
}, 0);

state$.subscribe(val => console.log(val));

dispatch({
  type: 'ADD',
  number: 10,
});

dispatch({
  type: 'SUBTRACT',
  number: 15,
});

dispatch({
  type: 'SUBTRACT',
  number: 0,
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.0/Rx.js"></script>
like image 39
Lukas Neicelis Avatar answered Oct 21 '22 13:10

Lukas Neicelis