簡體   English   中英

Angular 表:來自日期范圍主題的管道可觀察數據

[英]Angular Table: piping observable data from a date range subject

我有一個按預期工作的代碼,但我懷疑代碼是否錯誤,它只是由於未記錄的功能而偶然工作,或者代碼是正確的並且它按設計預期工作。

我想要的是一個更新另一個組件表的數據源的材料日期范圍選擇器。

我假設通過模板app.component.html傳遞值的部分

  <app-mytable ID="MyTable1" 
    [Start]="rangeFormGroup.value.start" 
    [End]="rangeFormGroup.value.end" ></app-mytable>

然后將這些值從表mytable.component.ts轉發到mytable-datasource.ts

  private _Start: Date | undefined;
  @Input()
  public get Start(): Date | undefined {
    return this._Start;
  }
  public set Start(value: Date | undefined) {
    this._Start = value;
    this.dataSource.start.next(value);
  }
  private _End: Date | undefined;
  @Input()
  public get End(): Date | undefined {
    return this._End;
  }
  public set End(value: Date | undefined) {
    this._End = value;
    this.dataSource.end.next(value);
  }

正在工作並且正確。

現在在數據源中我有 2 個日期/主題

export class MytableDataSource extends DataSource<MytableItem> {
  data: MytableItem[] = EXAMPLE_DATA;
  start: Subject<Date> = new Subject<Date>();
  end: Subject<Date> = new Subject<Date>();

最后,這是我的疑問和問題,所有關於我觸發更改的部分。

  let _start : Date 
  let _end : Date
  this.start.subscribe(update => _start = update);
  this.end.subscribe(update => _end = update);
  return merge(
      observableOf(this.data) ,this.paginator.page, this.sort.sortChange, 
      this.start.pipe(), this.end.pipe())
    .pipe(map(() => {
      console.log('merge piped');
      return this.getPagedData(
        this.getSortedData(
        this.filterByDateRange(_start, _end,
          [...this.data ])));
    }));

即使我的測試表明結果是正確的並且更改傳播得很好,我也無法在代碼中看到什么保證_start_end的更新總是在它們傳遞給filterByDateRange之前完成。

我認為括號內的那些是兩個異步事件,因此第一個動作( update =>...在開始/結束subscribe之后)和第二個動作( this.filterByDateRange(...在開始之后)的順序如何/end's pipe() in the merge ) 真的保證以正確的順序發生,后者總是在前者之后?

我更相信以下是正確的方法,即用 map 替換訂戶,如類似答案中所述。

您不能從 subscribe 返回 observable,但如果您使用 map 而不是 subscribe 則返回 Observable。

  let _start : Date 
  let _end : Date
  return merge(
      // observableOf(this.data) ,
      // BTW you don't need this above
      this.paginator.page, this.sort.sortChange, 
      this.start.pipe(map(update => {
        _start = update;
        return update;})), 
      this.end.pipe(map(update => {
        _end = update;
        return update;})))
    .pipe(map(() => {
      console.log('merge piped');
      return this.getPagedData(
        this.getSortedData(
        this.filterByDateRange(_start, _end,
          [...this.data ])));
    }));

由於 _start/_end 更新是副作用,我相信最好只在唯一的最終合並階段發生它們:

  let _start : Date 
  let _end : Date
  return merge(
      this.paginator.page, this.sort.sortChange, 
      this.start.pipe(map(update => {
        return {'start':update};})), 
      this.end.pipe(map(update => {
        return {'end':update};})))
    .pipe(map((merged) => {
      if ('start' in merged ) {
        _start = merged.start;
      }
      if ('end' in merged ) {
        _end = merged.end;
      }
      console.log('merge piped');
      return this.getPagedData(
        this.getSortedData(
        this.filterByDateRange(_start, _end,
          [...this.data ])));
    }));

有損背壓

映射可能比原始訂閱者更好的另一個原因是應用去抖動(對用戶輸入),以便消費者(可能正在運行的查詢)不會不知所措(但這不在這個問題的 scope 范圍內)。

IO 效果

另一個真實世界的例子是 http IO 效果,這將需要(在功能語言字典中)一個 flatMap (已過時,它是mergeMap )與一個緩存組成(當日期范圍過濾器包含在先前獲取的數據中時)

  let _start : Date 
  let _end : Date
  return merge(
      this.paginator.page, this.sort.sortChange, 
      this.start.pipe(map(update => {
        return {'start':update};})), 
      this.end.pipe(map(update => {
        return {'end':update};})))
    .pipe(map((merged) => {
      var mustLoad = false;
      if ('start' in merged ) {
        if (merged.start) {
          if (!_start || _start.getTime() > merged.start.getTime()) {
            mustLoad = true;
          }
          _start = merged.start;  
        }
      }
      if ('end' in merged ) {
        if (merged.end) {
          if (!_end || _end.getTime() < merged.end.getTime()) {
            mustLoad = true;
          }
          _end = merged.end;  
        }
      }
      if (mustLoad && _start && _end) {
        return {"cache":[], "mustLoad":true}
      } else {
        mustLoad = false;
      }
      return {"cache":this.data, "mustLoad":false};
    })).pipe(mergeMap ((a) => {
      if (a.mustLoad) {
        if (!this.database) {
          console.log("Database not initialized!");
          return observableOf([]);
        }
        console.log('firing API call');
        return this.database.getBrokerFees(_start,_end);
      }
      return observableOf( a.cache);
    })
      ).pipe(map(a => {
        const filtered = this.filterByDateRange(_start, _end, a);
        this.data = filtered;
        const sorted = this.getSortedData(filtered);
        var paged = [...sorted] // needs copy of sorted 
        paged  = this.getPagedData(paged); // paged works inline and modify input
        return paged;
      }));

其他高階運算符

另請參閱高階 RxJs 映射運算符的 綜合指南:switchMap、mergeMap、concatMap(和 excludeMap)。

此外,由於您正在處理反應式 Forms ,因此您必須意識到:

表單中的每個控件(選擇、輸入、復選框等)都有一個valueChanges屬性,一個我們可以訂閱的 Observable 以便觀察隨時間的變化並使用 RxJS 運算符以功能方式轉換值。

因此,我想如果您直接將可觀察的標准表單輸入到合並 map 中,您可以避免問題中的自定義日期主題,盡管您可能更喜歡已經定義的主題來實現您的特定緩存策略。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM