undefined
undefined

Reputation: 6844

Rx combineLatest wait for two observables to emit

Let's say I have a store who holds ids and entities, and I need to combine them when they changed.

const state = {
  ids: [],
  entities: {}
}
const store = new BehaviorSubject(state);

Observable.combineLatest(
   store.map(state => state.ids).distinctUntilChanged(),
   store.map(state => state.entities).distinctUntilChanged(),
   (ids, entities) => {
     return ids.map(id => entities[id])
   }
).subscribe(console.log);

store.next({ids: [1], entities: {1: {id: 1}}})

The problem with the above code is that the selector function will called twice because both the entities and the ids changed.

Is there any operator to solve this problem? If not, how can I create one that solves this?

I thought of a special test. To wait a certain time and unite their next() to one.

Note: It should support add, update, and delete.

The zip operator will solve, add and delete, because in this cases I'm updating both the ids and the entities, but update entity will not work.

Upvotes: 2

Views: 1729

Answers (1)

Bazinga
Bazinga

Reputation: 11194

The withLatestFrom operator should do the job.

store.map(state => state.entities).distinctUntilChanged().withLatestFrom(
  store.map(state => state.ids).distinctUntilChanged(), (entities, ids) => ids.map(id => entities[id])
).subscribe(console.log);


// Add    
store.next({
  ids: [1],
  entities: {
    1: {
      id: 1,
      name: 'A'
    }
  }
});

// Update

store.next({
  ...store.getValue(),
    entities: {
      1: {
        name: 'B'
      }
    }
});

// Delete
store.next({
  ids: store.getValue().ids.filter(id => id !== 1),
  entities: {}
});

Upvotes: 1

Related Questions