Compare most recent values from multiple BehaviorS

2019-03-03 09:12发布

问题:

Say I have this:

  isMatchedCountLessThanTotalCountMessage(){
       // I want to implement this
       // "returns" a string asynchronously
  }

  getMatchedEventsCount() {
    return this.dcs.matchCount.asObservable();
  }

  getTotalEventsCount() {
    return this.dcs.totalCount.asObservable();
  }

matchedCount and totalCount are like so:

  public matchCount = new BehaviorSubject<number>(0);
  public totalCount = new BehaviorSubject<number>(0);

these Observables fire integers as values change. Anytime a value is fired from either one, I want to compare the two most recent values from both, how do I do that?

What I want to do is return a boolean from the method

so I can display in the HTML:

 <div>{{(isMatchedCountLessThanTotalCountMessage() | async)}}</div>

I think Observable.zip might do the trick:

isMatchedCountLessThanTotalCountMessage(){
    return Observable.zip(
      this.getMatchedEventsCount(),
      this.getTotalEventsCount()
    )
    .subscribe(function(v){
      const intA = v[0];
      const intB = v[1];

        if(intA > intB)
         // but I don't know how to send a message the HTML from here
    });
  }

回答1:

You can easily use .map() function to transform the data you want:

isMatchedCountLessThanTotalCountMessage() {
    return Observable.combineLatest(
        this.getMatchedEventsCount(),
        this.getTotalEventsCount(),
    )
        .map(([intA, intB]) => {
            return intA > intB ? '(results ARE filtered)' : '(results are not filtered)'
        })
}


回答2:

This works, although we might be able to use something other than Observable.zip.

 isMatchedCountLessThanTotalCount() {
    return Observable.create(obs => {
      return Observable.zip(
        this.getMatchedEventsCount(),
        this.getTotalEventsCount()
      )
      .subscribe(v => {
        if ((v[1] - v[0]) > 0) {
          obs.next('(results ARE filtered)')
        }
        else {
          obs.next('(results are not filtered)');
        }
      });
    });
  }

and there is actually a simpler way to do that using what's called a "projection function":

  isMatchedCountLessThanTotalCount() {
    return Observable.combineLatest(
      this.getMatchedEventsCount(),
      this.getTotalEventsCount(),
      function (one, two) {
        if ((two - one) > 0) {
          return '(results ARE filtered)'
        }
        return '(results are not filtered)';
      }
    )
  }

Observable.combineLatest() is similar to Observable.zip() but will fire upon the first new value, it doesn't wait for new values to come from all observables.