1

The problem that I'm trying to solve is:

A) get some data from backend then set it as global variable (let's say)

B) if data from A) is set then react for an button click on UI and emit next value on BehaviourSubject

C) when the data from A) is set and button from B) have been clicked do something else.

Currently my solution is

const loadData$ = this.getData().pipe(tap(x => save data to global variable));
const updateNumber = new BehaviourSubject(undefined);
const updateNumber$ = updatePage.asObservable();

combineLatest([loadData$, updateNumber$]).subscribe(([_, someNumber]) => {
   this.something(someNumber)
})

The problem with this solution is: combineLatest reacts on loadData$ but first value returned from updateNumber$ is undefined so this.something(param) is invoked with undefined param. I can of course check if someNumber != undefined but I'am thinking about usage of some fancy rxjs operators. Any ideas ?

  • 1
    You are using BehaviorSubject with `undefined` as the first value emitted. You could use ReplaySubject(1) instead, then your `combineLatest` won't emit until your subject emits its first value. – Steve Holgado Nov 17 '21 at 23:29
  • What is the expected behavior when the data is NOT available and the buttons are clicked. Should they be ignored? – Pankaj Nov 18 '21 at 04:18
  • @Pankaj yes it should be ignored. The 'global variable' have to be set If it is not there nothing should happen. – Mr.FloppyDisk Nov 18 '21 at 06:37

1 Answers1

1

Instead of using combineLatest, you can use a combination of withLatestFrom and BehaviorSubject

let globalStream = new BehaviorSubject<any>(null);
let globalStream$ = globalStream.asObservable();


this.getData().subscribe((s) => {
  console.log('Setting Global state: ', s);
  globalStream.next(s);
});

let source1 = button1Click$.pipe(
  withLatestFrom(globalStream$),
  map(([c, data]) => {
    return data;
  }),
  filter((t) => !!t)
);

let source2 = button2Click$.pipe(
  withLatestFrom(globalStream$),
  map(([c, data]) => {
    return data;
  }),
  filter((t) => !!t)
);

source1.subscribe((s) => console.log('Button 1 handled', s));
source2.subscribe((s) => console.log('Button 2 handled', s));

Here's a stackblitz demo.

Pankaj
  • 538
  • 4
  • 13
  • I've explicitly used 2 different subscription for source1, source2., but they can be merged in a single observable using `merge` opertor – Pankaj Nov 18 '21 at 19:30