簡體   English   中英

使用來自對話框的輸入訂閱可觀察的異步地圖結果,使用地圖的結果到路由

[英]Subscribe to observable, async map result with input from dialog, use result from map to route

我正在調用一個 API 服務,它返回一個 Observable - 包含一個元素數組。

apiMethod(input: Input): Observable<ResultElement[]>

從這里我一直在選擇數組的第一個元素,訂閱那個。 然后使用該元素路由到另一個頁面,如下所示:

this.apiService
  .apiMethod(input)
  .pipe(map((results) => results[0])
  .subscribe(
    (result) => {
      return this.router.navigate('elements/', result.id)
  }
)

這工作得很好。

問題是,我不想只使用第一個元素,我想要一個 MatDialog 或其他類似的元素彈出,並為用戶提供選擇哪個元素的選項,然后路由到正確的元素。

如果列表只包含一個元素,則不應顯示對話框,並且應立即路由用戶。

我試圖在.pipe(map())函數中打開一個對話框,但是subscribe()發生在我從用戶那里得到答案之前,導致它失敗。 我不確定這是否是正確的方法。 你們中的任何人將如何解決這個問題?

我將使用以下方法解決它:

  1. 通過訂閱獲取數據(不使用管道)。 並將這些數據保存在組件變量中
options: any;

this.apiService
  .apiMethod(input)
  .subscribe(
    (result) => {
       if (result.length === 1) {
         this.router.navigate([result[0]]);
         return;
       }
       options = result;
  }
)
  1. 在模態上使用 ngIf(以選項數組的長度為條件 > 0,在接收到數據時顯示具有不同選擇的組件
<modal-component *ngIf="options.length > 0"></modal-component>
  1. 當用戶(單擊)模式中的選項時,使用路由器進行重定向。
html
<div (click)="redirect(value)">option 1</div>

ts
redirect(value) {
    this.router.navigate([value]);
}

那將是最直接的

兩種可能的選擇:

  1. 通過用戶輸入或通過一個元素獲取 api 結果的副作用,為所選結果設置一個主題。
  2. 跟蹤組件的整體狀態並在狀態中設置 selectedResult 時做出適當的響應。

下面的示例是使用 Observable 跟蹤組件狀態的草圖。

  • 狀態中有兩個輸入流,來自 api 的結果和所選結果的用戶輸入。
  • 每個流都被轉換為一個 reducer 函數,該函數將修改整體狀態。
  • UI 應該通過異步管道訂閱這個狀態,在適當的時候顯示模態,並通過主題從事件更新更新狀態。
  • 當 selectedResult 具有值時,重定向應該對狀態更改產生影響。
readonly getResultsSubject = new Subject<MyInput>();
readonly resultSelectedSubject = new Subject<ResultType>();

private readonly apiResults$ = this.getResultsSubjects.pipe(
  switchMap((input) => this.apiMethod(input))
);

readonly state = combineLatest([
  this.apiResults$.pipe(map(results => (s) => results.length === 1 
    ? { ...s, results, selectedResult: x[0], showModal: false }
    : { ...s, results, showModal: results.length > 1 })),
  this.resultSelectedSubject.pipe(map(selectedResult => (s) => ({ ...s, selectedResult })))
]).pipe(
  scan((s, reducer) => reducer(s), { }),
  shareReplay(1)
);

ngOnInit() {
  this.state.pipe(
    filter(x => !!x.selectedResult)
  ).subscribe(x => this.router.navigate('elements/', x.selectedResult.id));
}

我最近一直在使用這種模式。 它使得狀態的動作和屬性的數量增長變得非常容易。

我將創建一個DialogComponent ,它將選擇列表作為輸入,並在關閉時發出所選項目。

然后,創建一個輔助方法(可能稱為promptUser ), promptUser返回一個發出所選值的可觀察對象:

this.apiService.apiMethod(input)
    .pipe(
        switchMap(results => results.length > 1
            ? this.promptUser(results)
            : of(results[0])
        )
    )
    .subscribe(
        result => this.router.navigate('elements/', result.id)
    );

這里我們簡單地使用switchMap來返回一個發出正確項目的 observable。 如果長度大於 1,我們返回顯示對話框並發出所選項目的輔助方法,否則只發出第一個(唯一)項目。 請注意,我們在 switchMap 中使用of包裝了普通值,我們需要返回 observable。

在任何一種情況下,您的訂閱回調都會發出和接收所需的項目。

暫無
暫無

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

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