Как сделать второй звонок по rx js без вложенности подписки - PullRequest
0 голосов
/ 13 июля 2020

Привет, я пытаюсь разобраться с rx js in angular 9, и я пытаюсь сделать вызов условно на основе ответа наблюдаемого, но, похоже, не могу заставить его работать без подписки на вложенность. Я прочитал несколько статей, включая this и this , но я не могу решить свою проблему.

В моем чтении я также прочитал this SO post

Метод confirmed() в DialogConfirmService срабатывает при нажатии кнопки подтверждения

Обратите внимание, что я пробовал более двух рефакторов, но опубликованные являются примерами того, что Я пытался.

Мое текущее рабочее решение (я хочу уйти от вложенных подписок)

this.dialogConfirmService
    .confirmed()
    .pipe(take(1))
    .pipe(map(x => {
             this.isSaving = true; 
             return x; 
          })
     )
    .subscribe(confirmed => {
      if (confirmed) {
        this.myService.save('', '')
                      .pipe(take(1))
                      .subscribe(
                            (data) => this.onSuccess(data),
                            (error) => this.handleError(error)
                      );
      }
    });

Ошибка моего рефакторинга 1

this.dialogConfirmService
        .confirmed()
        .pipe(take(1))
        .pipe(
          map(x => {
              this.isSaving = true;
              console.log(x);
              return x;
            }
          ),
          mergeMap(cv =>
            this.myService.save(
              this.rulesetForm.controls.name.value,
              JSON.parse(this.rulesetForm.controls.definiation.value)
            )
        )).subscribe(j => this.isSaving = false);

Ошибка моего рефакторинга 2

onSave(): void {
    this.dialogConfirmService
            .confirmed()
            .pipe(take(1))
            .pipe(
              flatMap(confirmed => this.onConfirm(confirmed)),
            );
}

  private onConfirm(confirmed: any) {
    if (confirmed) {
      this.isSaving = true;
      this._ruleSetMapperService.save(
        this.rulesetForm.controls.name.value,
        JSON.parse(this.rulesetForm.controls.definiation.value)
      );
    } else {
      return Observable.create(function(observer) {
        observer.next(confirmed);
        observer.complete();
      });
    }
  }

Ниже приведен другой код, который вызывается (для полноты)

диалоговая служба

..other stuff...
export class DialogConfirmService {

  ...other stuff...

  public confirmed(): Observable<any> {

    return this.dialogRef
               .afterClosed()
               .pipe(take(1),
                     map(res => {
                        return res;
                      })
                );
  }
}

Моя спасательная служба

export class MyService {
  save(rsn: string, rsd: string): Observable<any> {
    ...other stuff... (generates the body)

    return this._http.post('myUrl', JSON.stringify(body), { headers: this.headers });
 }
}

1 Ответ

6 голосов
/ 13 июля 2020

Вот несколько альтернатив, с помощью которых вы можете избежать вложенных подписок:

1)

this.dialogConfirmService
            .confirmed()
            .pipe(
                tap(() => (this.isSaving = true)),
                switchMap((confirmed) =>
                    confirmed ? this.myService.save('', '') : of(null)
                ),
                catchError((error) => throwError(error))
            )
            .subscribe((data) => this.onSuccess(data));

Rx JS операторы:

tap - используется для побочных эффектов;

switchMap - завершает предыдущую наблюдаемую и подписывается на новую (комбинация операторов switch и map) в зависимости от условия. Помните, что даже если условие ложно, вам всегда нужно охватить оба сценария ios.

catchError, throwError - ну, используется для обработки ошибок

2.

this.dialogConfirmService
            .confirmed()
            .pipe(
                filter((confirmed) => !!confirmed),
                tap(() => (this.isSaving = true)),
                switchMap(() => this.myService.save('', '')),
                catchError((error) => throwError(error))
            )
            .subscribe((data) => this.onSuccess(data));

filter - в этом случае он будет подписываться на следующий наблюдаемый, только если условие истинно.

3.

this.dialogConfirmService
            .confirmed()
            .pipe(
                switchMap((confirmed) =>
                    iif(() => confirmed, this.myService.save('', ''))
                ),
                catchError((error) => throwError(error))
            )
            .subscribe((data) => this.onSuccess(data));

iif - это похож на тернарный оператор. Он принимает функцию условия и две наблюдаемые объекты, однако вторая наблюдаемая не требуется.

Что касается http-вызова, который вы делаете, вы не должны структурировать полезную нагрузку.

...