0

In my web app's client code I have a class responsible for a bunch of websocket IO. This class has a global itemUpdatedObservable that various parts of the UI can subscribe to to do little things. There is also a public function UpdateItem which returns a promise-esq Observable. When the item is updated in response to the call to UpdateItem I want both the returned observable and global observable to emit. The returned observable should also complete after emitting.

I have come up with this solution:

// Singleton
class API {

readonly itemUpdatedObservable: Observable<Item>;
private pendingItemUpdates: { [id: string]: Observer<Item> };

constructor() {
  this.itemUpdatedObservable = new Observable(observer => {
    socketio.on('itemUpdated', res => {
      // do a bunch of validation on item
      // ...

      if (!res.error) {
         observer.next(res.item);
      } else {
         observer.error(res.error);
      }

      let pendingObs = pendingItemUpdates[res.id]
      if (pendingObs) {
        if (!res.error) {
           pendingObs.next(res.item);
        } else {
           pendingObs.error(res.error);
        }
        pendingObs.complete()
        delete pendingItemUpdates[res.id];
      }
    })
  });
  this.pendingItemUpdates
}

public UpdateItem(item: Item): Observable<Item> {
  const o = new Observable(observer => {
    let id = uniqueId(); // Some helper somewhere.
    this.pendingItemUpdates[id] = observer;
    socketio.emit('updateitem', {item: item, id: id});
  }).publish();
  o.connect();
  return o;
}
}

My question is if there is a cleaner, shorter way of doing this? I have something like 10+ observables in addition to itemUpdatedObservable that all are events for different Object types. This code is messy and unwieldy especially when I am writing it 10x over. Is there a way to streamline the two observables such that I am only calling observable.next(...) or observable.error(...) once?

The above code blob is a simplification of my actual code, there is a lot more validation and context-specific values and parameters in reality.

Samuel Davidson
  • 783
  • 6
  • 16

1 Answers1

0

Maybe you can start with creating some reusable socket function which return observable.

const socketOn = (event) => {
   return Observable.create(obs => {
    socketio.on(event, res => {
      if (!res.error) {
        obs.next(res.item);
      } else {
        obs.error(res.error);
      }
    })
  }).share()
}

// usuage 
itemUpdated$=socketOn('itemUpdated')
itemUpdated$.map(res=>...).catch(e=>...)
Fan Cheung
  • 10,745
  • 3
  • 17
  • 39