如何在等待从 Angular 服务中获取数据的可观察对象时显示加载旋转器

Ray*_*lor 7 angular

我已经设置了一个可观察的服务来帮助我保存数据,但是我需要一种方法来在数据等待来自可观察的数据时显示加载旋转器。

我的服务:

imports [...]

import { Observable, BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class OrganisationsService {
  private organisations$ = new BehaviorSubject<Organisation[]>([
    {
      [...]
    }
  ]);

  constructor(private http: HttpClient) {
    this.http
      .get(
        environment.apicall
      )
      .subscribe((data) => this.organisations$.next(data['organisations']));
  }

  getList(): Observable<Organisation[]> {
    return this.organisations$.asObservable();
  }
Run Code Online (Sandbox Code Playgroud)

这是我的组件:

    imports ...

    import UIkit from 'uikit';
    import { Observable } from 'rxjs';

    @Component({
      selector: 'app-organisationlist',
      templateUrl: './organisationlist.component.html',
      styleUrls: ['./organisationlist.component.css']
    })
    export class OrganisationlistComponent implements OnInit {

      public loading = true;

      public organisations$: Observable<Organisation[]>;

      constructor(public organisationsService: OrganisationsService) {}

      ngOnInit() {
        this.getData().then(() => {
          this.loading = false;
        });
      }

      async getData() {
        this.organisations$ = this.organisationsService.getList();
      }
}
Run Code Online (Sandbox Code Playgroud)

这是我的布局(使用 Uikit):

  <div *ngIf="loading" uk-spinner></div>
  <div>
    <ul class="uk-list">
      <li *ngFor="let organisation of organisations$ | async">
        {{ organisation.name }}
      </li>
    </ul>
  </div>
Run Code Online (Sandbox Code Playgroud)

显然,该getData函数虽然声明为异步,但实际上并不是异步的,并且会立即返回。“false”OnInit 也是如此this.loading,因此它不会显示。

有很多答案表明当订阅发生在组件中时这可能如何工作,但因为这是服务中的共享数据,所以我找不到在设置为this.loadingfalse 之前等待数据的方法。

非常感谢。

Ray*_*lor 10

感谢大家的回复,但这些建议都没有达到问题中概述的目的,但我确实研究了一种解决方案并最终得到了解决方案。开始了:

在服务中,我创建了一个名为的新 Observableloading$并将其设置为new BehaviorSubject<boolean>(true);

然后我创建了一个吸气剂:

getLoading(): Observable<boolean> { return this.loading$; }

然后,我将 HTTP 调用包装在订阅的第三个参数(onCompleted函数)中true,然后设置加载。false

所以服务看起来像这样:

import { Observable, BehaviorSubject, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class OrganisationsService {
  private organisations$ = new BehaviorSubject<Organisation[]>([
    {
      [...]
    }
  ]);

  //initiate the new Loading variable via BehaviorSubject and set it to "true" from the beginning.
  public loading$ = new BehaviorSubject<boolean>(true);

  constructor(private http: HttpClient) {

    //set the loading$ to true again just before we start the HTTP call
    this.loading$.next(true);


    this.http
      .get(environment.apicall)
      .subscribe(

        //onNext method, where we get the data
        (data) => this.organisations$.next(data['organisations']),

        //onError method (Blank for now)
        () => {},

        //onComplated method, now that we have the data we can set the loading to false
        () => {
          this.loading$.next(false);
        }
      );
  }

  getLoading(): Observable<boolean> {
    return this.loading$;
  }

  getList(): Observable<Organisation[]> {
    return this.organisations$;
  }
Run Code Online (Sandbox Code Playgroud)

请注意,在 HTTP 调用的 subscribe 方法中,我添加了一个空白的第二个方法(这是用于 onError),然后在第三个方法中,我添加了一个函数来将加载设置为 false: this.loading$.next(false);。这意味着当订阅完成时,Loading 现在将为 false。

然后在我的组件中,我得到loading$订阅:

      public loading$: Observable<boolean>;
      public organisations$: Observable<Organisation[]>;

      constructor(public organisationsService: OrganisationsService) {}

      ngOnInit() {
        this.getData();
      }

      async getData() {

        //initially loading$ will be true because the service makes it so
        this.loading$ = this.organisationsService.getLoading();

        //when this completes, loading$ will be set to false via the service
        this.organisations$ = this.organisationsService.getList();
      }
Run Code Online (Sandbox Code Playgroud)

在我看来:

  <div>
    <div uk-spinner *ngIf="loading$ | async"></div>
    <ul class="uk-list">
      <li *ngFor="let organisation of organisations$ | async">
        {{ organisation.name }}
      </li>
    </ul>
  </div>
Run Code Online (Sandbox Code Playgroud)