Загрузка спиннера не отображается при выполнении HTTP-запроса в Angular - PullRequest
1 голос
/ 24 апреля 2020

Я делаю веб-приложение в Angular 8 и хочу показать спиннер загрузки при выполнении HTTP-запроса.

Спиннер загрузки не отображается в моей реализации, и я не смог найти причина.

Сервис

@Injectable()
export class UserService {

  // Caching
  private bsResource: BehaviorSubject<string[]> = new BehaviorSubject([]);
  private readonly resources$: Observable<string[]> = this.bsResource.asObservable();

  constructor(
    private http: HttpClient
  ) {
  }

  // Calling this method the loading spinner is not showing.
  getResources(): Observable<string[]> {
    if (this.bsResource.getValue().length === 0) {
      this.fetchResourceList().toPromise().then(res => this.bsResource.next(res));
    }

    return this.resources$;
  }

  // The loading spinner appears if I use this method directly and make this method public.
  private fetchResourceList(): Observable<string[]> {
    return this.http.get<string[]>('MY_URL');
  }
}

Компонент:

@Component({
  templateUrl: './create-new.component.html',
  styleUrls: ['./create-new.component.scss']
})
export class CreateNewComponent {
  resourceList$: Observable<string[]> = this.service.getResources();

  constructor(
    private service: UserService
  ) { }
}

Шаблон

<div class="form-group">
  <label for="resourceSelect">* Resources</label>
  <div *ngIf="resourceList$ | async as resourceList; else loading">
     <ng-container *ngIf="resourceList.length; else noResults" >
        <div *ngFor="let r of resourceList; index as i">
          <!-- Show the result using checkboxes -->
        </div>
     </ng-container>
  </div>
</div>

<ng-template #loading>
  <br/>
  <div class="spinner-border spinner-border-sm text-muted" role="status">
    <span class="sr-only">Loading...</span>
  </div>
</ng-template>

<ng-template #noResults>
  <div class="text-muted">No results.</div>
</ng-template>

Я не понимаю, почему при использовании this.service.getResources() загрузочный счетчик не отображается, и если я использую this.service.fetchResourceList() загрузочный счетчик отображается правильно.

Моя цель - правильно показать загрузочный счетчик, используя предоставленный мной пример, и сохранить метод, который я вызываю в моем компоненте.

1 Ответ

1 голос
/ 27 апреля 2020

Я потратил время, чтобы воспроизвести его в песочнице, но, наконец, обнаружил, что проблема связана с инициализацией вашего BehaviorSubject. Первое значение bsResource равно []. Таким образом, в вашем *ngIf, когда канал async подписывается на него, он получает значение [], которое является правдивым, поэтому *ngIf мгновенно истинно и никогда не вызывает блок else (загрузка).

Все, что вам нужно сделать, это инициализировать BehaviorSubject с нулевым значением (и затем исправить код, используя его, чтобы быть нулевым):

private bsResource: BehaviorSubject<string[]> = new BehaviorSubject(null);

И когда вы используете его :

const cachedValue = this.bsResource.getValue();
if (!cachedValue || cachedValue.length === 0) {
  this.fetchResourceList().subscribe(res => this.bsResource.next(res));
}

Я говорю это снова, вы не должны использовать Promises, использовать .subscribe, который работает так же, как toPromise().then. Вы никогда не должны использовать Promise. .toPromise полезно только при обновлении Angular, где большая часть кода использует Promises и не хочет обновлять весь код сразу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...