【问题标题】:Angular2 / RxJS - updating variable after getting data from Http observableAngular2 / RxJS - 从 Http observable 获取数据后更新变量
【发布时间】:2016-04-11 16:20:45
【问题描述】:

我想在数据开始从 API 下载时打开我的加载器图标(例如微调器)isLoaderEnabled,并在成功接收时将其关闭。什么是关闭它的正确方法?

这是我的以下代码。

我的组件:

this.isLoaderEnabled = true;
this.meetingService.getList();

我的服务:

getList() {
  this._http.get('../fake-data/someFile.json')
    .map(response => response.json())
    .subscribe(
      data => {
        this.dataStore.meetingList = data;
        this.meetingListObserver.next(this.dataStore.meetingList);
      },
      err => console.log('>>>', 'Could not load meetings list. Error: ', err),
      () => console.log('>>>', 'Done with getting meetings list.')
    );
}

谢谢。

【问题讨论】:

    标签: typescript angular


    【解决方案1】:

    我认为您的问题比乍一看更棘手;-) 事实上,XHR 不支持流式传输,因此当在 subscribe 方法中注册的第一个回调被调用时,您已经收到了所有数据。

    也就是说 XHR 支持 onprogress 事件(请参阅此 plunkr:http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview)。这允许获取有关下载进度的提示。 Angular2 不支持开箱即用,但您

    @Injectable()
    export class CustomBrowserXhr extends BrowserXhr {
      constructor(private service:ProgressService) {}
      build(): any {
        let xhr = super.build();
        xhr.onprogress = (event) => {
          service.progressEventObservable.next(event);
        };
        return <any>(xhr);
      }
    }
    

    并使用扩展覆盖BrowserXhr 提供程序:

    bootstrap(AppComponent, [
      HTTP_PROVIDERS,
      provide(BrowserXhr, { useClass: CustomBrowserXhr })
    ]);
    

    进度服务可以这样实现:

    export class ProgressService {
      progressEventObservable:Subject<any> = new Subject();
    }
    

    您的服务可以订阅进度服务,以便在下载实际开始时收到通知(即第一次为请求调用progressEventObservablenext 方法):

    getList() {
      var subscription = this.progressService.subscribe(event => {
        if (!this.spinner) {
          this.spinner = true;
        }
      });
      this._http.get('../fake-data/someFile.json')
        .map(response => response.json())
        .do(val => this.spinner = true)
        .subscribe(
          data => {
            this.dataStore.meetingList = data;
            this.meetingListObserver.next(this.dataStore.meetingList);
          },
          err => (...),
          () => {
            this.spinner = false;
            subscription.unsubscribe();
          })
        );
    }
    

    编辑

    如果您想在组件而不是服务中使用微调器。您可以使用专用的 observable / subject,如下所述:

    spinner$: Subject<boolean> = new Subject();
    spinner: boolean = false;
    
    getList() {
      var subscription = this.progressService.subscribe(event => {
        if (!this.spinner) {
          this.spinner = true;
          this.spinner$.next(this.spinner); // <-------
        }
      });
      this._http.get('../fake-data/someFile.json')
        .map(response => response.json())
        .do(val => this.spinner = true)
        .subscribe(
          data => {
            this.dataStore.meetingList = data;
            this.meetingListObserver.next(this.dataStore.meetingList);
          },
          err => (...),
          () => {
            this.spinner = false;
            this.spinner$.next(this.spinner); // <-------
            subscription.unsubscribe();
          })
        );
    }
    

    该组件可以订阅spinner$ 以获得更改通知:

    @Component({
      (...)
    })
    export class SomeCOmponent {
      constructor(private meetingService:MeetingService) {
        this.meetingService.spinner$.subscribe((spinner) {
          this.isLoaderEnabled = spinner;
        });
      }
    }
    

    【讨论】:

    • 还有一件事,我的组件中有我的微调器(不是服务)。这会改变一些事情吗?
    • 不客气!如果您的微调器在其中,您需要订阅该组件...
    • 您能详细说明一下吗?我有两个文件,一个是组件(这是微调器获取状态真假的地方;调用服务),另一个是服务 - 请参阅最初的问题。
    • 是的,当然!我更新了我的答案以接近你的课程。
    • Thierry 非常感谢,再次感谢您!我会深入研究。
    【解决方案2】:
    getList() {
      this._http.get('../fake-data/someFile.json')
        .map(response => response.json())
        .do(val => this.spinner = true)
        .subscribe(
          data => {
            this.dataStore.meetingList = data;
            this.meetingListObserver.next(this.dataStore.meetingList);
          },
          err => console.log('>>>', 'Could not load meetings list. Error: ', err),
          () => this.spinner = false)
        );
    }
    

    【讨论】:

    • 谢谢。再次:) 我怀疑这会起作用,因为我将组件和服务放在单独的文件中?
    • 我明白了。 Thierry 的回答展示了如何使用 Observable 通知感兴趣的组件。
    【解决方案3】:

    你需要做一些小技巧才能让它正常工作:

        //use Observable.from as lock trigger BEFORE request is sent
        var request:Observable<Response> = Observable.from([1], null).do(()=>
        {
            lock.lock();
        }).flatMap(()=>
        {
            //use finally to unlock in any case
            return this.http.post(url, body, options).finally(()=>
            {
                lock.unlock();
            });
        });
        //share sequence to avoid multiple calls when using several subscribers
        return request.share();
    

    【讨论】:

      【解决方案4】:

      如果您的组件subscribe()s 到meetingListObserver,只需在订阅回调函数中将其关闭即可。

      如果没有,则向服务添加另一个 Observable 或 Subject 并让组件订阅它。当数据从服务返回时,在 Observable 或 Subject 上调用 next()。有关在服务中使用 Subject 的示例,请参阅https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-28
        • 1970-01-01
        • 2017-09-04
        • 1970-01-01
        • 2016-07-23
        • 2017-12-09
        • 2018-10-12
        相关资源
        最近更新 更多