Angular RxJS - установить значение конвейера valueChanges равным нулю, пока наблюдаемое не разрешится - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь передать значение ValueChanges из select, чтобы запустить соответствующий запрос API и показать спиннер, пока ответ не получен.Кроме того, я пытаюсь использовать publish() и refCount(), чтобы я мог использовать эту наблюдаемую трубу async в нескольких местах в моем шаблоне.

my-component.ts

ngOnInit() {
  this.results$ = this.selectControl.valueChanges.pipe(
    startWith('hard'),
    switchMap((evalStrategy: 'hard' | 'soft') => this.apiService.getResults(evalStrategy)),
    publish(),
    refCount()
  );
}

my-component.html

<mat-progress-spinner *ngIf="!(results$ | async)"></mat-progress-spinner>

<div *ngIf="results$ | async">
   <p>Name {{(results$ | async).name}}</p>
   <small>{{(results$ | async).description}}
</div>

В идеале, я ожидал бы, что этот код будет работать и только сработает только 1 запрос к серверу.

Но я получаю Cannot read property 'name' of null: (

Если я сделаю следующее изменение в my-component.html

<mat-progress-spinner *ngIf="!(results$ | async)"></mat-progress-spinner>

<div *ngIf="(results$ | async) as results">
   <p>Name {{(results).name}}</p>
   <small>{{(results).description}}
</div>

Тогда он работает нормально, и единственный запрос на выключение сервера 1 для сервера. Но когда вы изменяете опцию выбора, results$ | async больше не оценивается как null, пока не станет доступно новое значение., он остается со старым значением, а затем внезапно заменяет его на обновленное.

1 Ответ

0 голосов
/ 27 августа 2018

В идеале вы хотите отделить переменные - чтобы контекст был понятнее - статус loading и окончательный results - это две разные вещи.Делая предположение, что results равны null, равно status, загрузка может быть опасной, поскольку они принципиально отличаются.Например, что происходит, если есть ошибка?Это значит, что results равно нулю, а status больше не загружается.Если следовать вашей реализации, ваш спиннер будет постоянно загружаться при возникновении ошибки.А также он может столкнуться с сценарием, который вы описали: вы теряете состояние loading, потому что теперь его больше нет null, и ваш счетчик никогда не загрузится после первого начального запроса.

Это такжесвоего рода избыточный (бессмысленный) сброс вашего results на null каждый раз, когда вы меняете форму.Технически ваши результаты не null.У него есть результаты.Просто результаты не самые последние.

Вместо этого используйте тему для выделения значений:

private isLoading = new BehaviourSubject<boolean>(false);

, а в своем компоненте просто используйте .tap(), чтобы изменить состояние Subject:

this.results$ = this.selectControl.valueChanges.pipe(
    startWith('hard'),
    tap(() => this.isLoading.next(true)), //sets loading to true, we are firing our api request!
    switchMap((evalStrategy: 'hard' | 'soft') => this.apiService.getResults(evalStrategy)),
    tap(() => this.isLoading.next(false)), //api finished fetching, stop the spinner!
    catchError(() => this.isLoading.next(false)), //this is up to you on how you want to do error handling.
    publish(),
    refCount(),
);

и получите свой HTML, чтобы привязать к нему:

<mat-progress-spinner *ngIf="isLoading"></mat-progress-spinner>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...