Rxjs 中没有更新主题

Updation to subject is not happening in Rxjs

我正在尝试通过组件的方法更新 RxJS 主题。但它并没有正常发生。

cricketData$ = new Subject<string>();

ngOnChanges() {
  this.cricketData$
    .asObservable()
    .pipe(
      tap(() =>
        console.log(
          'Triggering REST call for cricket tab with the year ',
          this.year
        )
      ),
      take(1)
    )
    .subscribe();
  this.cricketData$.next('sachin');
}

updateCricketData() {
   this.cricketData$.next('dravid');
}

如果我删除 take 运算符,主题就会更新。但是从下拉列表中选择值时会触发多个服务调用。 RxJS 中是否有任何其他运算符/方法可以实现以下场景?

  1. 从下拉列表中选择值时仅触发一次服务调用
  2. 主题也通过组件的方法更新

请参考下面的 StackBlitz link。提前致谢。

编辑器 URL Stackblitz:EditorURL

应用程序 URL Stackblitz:AppURL

有两个问题。
第一个: ngOnChanges 触发多次,每次更改值时都会添加一个并行工作的新管道。 take(1) 使您之前的管道停止并且仅触发最近的管道 tab

ngOnInit(): void { // runs once
    this.cricketData$
      .asObservable()
      .pipe( // runs on every next
        tap(() =>
          console.log(
            'Triggering REST call for cricket tab with the year ',
            this.year
          )
        )
      )
      .subscribe();
  }

  ngOnChanges() {
    this.cricketData$.next('sachin'); // runs on every event on the page
  }

第二个问题:你真的想在页面有更新时在 ngChange 上触发这个功能,而不仅仅是下拉列表吗?在下拉列表中进行更改,然后您可以使用 Input set year(value: string)

的组合

example

    export class CricketComponent implements OnChanges {
  private _selectedYear: string;

  @Input() set year(value: string) {
    this._selectedYear = value;
    this.cricketData$.next('sachin'); // will trigger with every drop down change
  }

  cricketData$ = new Subject<string>();

  constructor() {}

  ngOnInit(): void {
    this.cricketData$
      .asObservable()
      .pipe(
        tap((value) =>
          console.log(
            'Triggering REST call for cricket tab with the year ',
            this._selectedYear,
            value
          )
        )
      )
      .subscribe();
  }

  ngOnChanges() {}

  updateCricketData() {
    this.cricketData$.next('dravid');
  }
}

如何为年份选择器使用表单控件,我们可以监听表单控件和您使用 combineLatest 创建的主题的变化,这将在它们中的任何一个发出时触发(只要它们至少发出过一次)。不知道您 how/when 的确切情况,您的主题最初已更新,所以我只是添加了一个 startWith(null) 值。将其应用于您的用例...

因此 parent 的表单控件:

year = new FormControl(2019);

和模板,我们在其中标记表单控件并将表单控件传递给 child:

<select [formControl]="year">
  <option value="2019">2019</option>
  <option value="2020">2020</option>
  <option value="2021">2021</option>
</select>

<app-cricket [year]="year"></app-cricket>

然后 child 在 OnInit 中与主题一起收听此内容:

ngOnInit() {
  combineLatest([
    this.year.valueChanges.pipe(startWith(this.year.value)),
    this.cricketData$.asObservable().pipe(startWith(null)),
  ]).pipe(
    switchMap(values => {
      return REST API request...
    })
  ).subscribe(result => console.log(result))
}

使用startWith使它们最初触发。记得取消订阅!!

STACKBLITZ(没有 switchMap