mezhik91
mezhik91

Reputation: 312

Strange behavior of BehaviorSubject with combineLatest

I'm new in Rxjs and I have faced with a strange behavior of BehaviorSubject with scan and combineLatest operator. Below the code of simple component:

import { Component, OnInit } from '@angular/core';
import { BehaviorSubject, of, combineLatest } from 'rxjs';
import { switchMap, scan} from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

  stream1 = new BehaviorSubject('');
  stream2 = new BehaviorSubject(0);
  result: any;
  counter = 1;

  sub: any;

  constructor() {}

  ngOnInit() {
    this.sub = this.stream2.pipe(
      scan((acc, v) => [...acc, v], []),
    );
    this.result = this.stream1.pipe(
      switchMap(data => combineLatest(of(data), this.sub))
    ).subscribe(val => console.log(val));
    this.stream1.next('init');
    this.stream2.pipe(scan((acc, v) => [...acc, v], [])).subscribe(val => console.log('Track Stream 2: ', val));
  }

  onClick() {
    this.stream2.next(this.counter++);
  }

  onClick2() {
    this.stream1.next('test ' + this.counter);
  }
}


<button (click)="onClick()">Test</button>
<button (click)="onClick2()">Test2</button>

As result of "this.result" stream I expect array where the first value - the latest value from 'this.stream1' and the 2nd value is an array with all values which were collected by 'this.sub', but on fact from "this.sub" I get only the latest value, as if my scan operator was ignored.. See attached img:

enter image description here

Could you please explain how to reach desired result? Thank you all!

Ps. Angular v6.0.7 and RxJs v6.2.1

Upvotes: 1

Views: 2380

Answers (1)

mezhik91
mezhik91

Reputation: 312

Seems like I found solution. I could fix it with shareReplay(0) operator, but I'm not sure if it the best solution, please correct me if so :)

  ngOnInit() {
    this.sup = this.stream2.pipe(
      scan((acc, v) => [...acc, v], []),
      shareReplay(0) // Solution
    );
    this.result = this.stream1.pipe(
      switchMap(ud => combineLatest(of(ud), this.sup))
      // withLatestFrom(this.sup)
    ).subscribe(val => console.log(val));
    this.stream1.next('second');
    this.stream2.pipe(scan((acc, v) => [...acc, v], [])).subscribe(val => console.log('Stream 2: ', val));
  }

Upvotes: 2

Related Questions