【问题标题】:Have component execute function after service http.get call is finished服务 http.get 调用完成后有组件执行功能
【发布时间】:2019-02-06 18:43:55
【问题描述】:

我在 angular2 中围绕 observables 和订阅时遇到了真正的麻烦。我目前遇到的问题如下:

我有一项服务,其中包含从 API 发布和获取数据的方法。服务被注入到一个组件中,该组件直接调用服务中的那些方法。该服务然后检索数据并自行存储,但我想在组件中处理该数据。在服务本身检索和存储数据后,我无法弄清楚如何让组件执行功能。

service.ts

import { Injectable } from 'angular2/core';    
import { Http } from 'angular2/router';

@Injectable()
export class Service {
    result: Object;

    constructor(http: Http) {
        this.http = http;
    }

    httpGet(url) {
        return this.http.get(url).subscribe(
            result => this.result = result.json(),
            error => console.log(error),
            () => {}
        )
    }
}

组件.ts

import { Component } from 'angular2/core';
import { Service } from './service';

@Component({
    ...
})
export class Component {
    formattedResult: Object;

    constructor(service: Service) {
        this.service = service;
        this.service.httpGet('/api')

        // How do I call format result on service.result only after it is completed?
        this.formatResult(service.result) // Need to execute this after the http call is completed

        // I want something like:
        this.service.httpGet('/api').then(() => formatResult(this.service.result));
    }

    formatResult(result) {
        this.formattedResult = result.map(x => x.length) // For example
    }
}

【问题讨论】:

  • @GünterZöchbauer 谢谢,它关闭了,但我想在服务中保留一个 .subscribe ,因为它自己存储该信息以供以后访问。一个 http.get 上不可能有两个 .subscribe(它会调用它两次)。除非接受的设计模式是仅在组件中使用 .subscribe 并从组件中显式设置服务变量?我只想保持服务和组件逻辑分离。
  • stackoverflow.com/a/34405243/215945 - 使用flatMap()回答链可观察对象。

标签: angular asynchronous rxjs observable


【解决方案1】:

回答我自己的问题:

在应用根目录中,使用以下命令导入 Rxjs:

import 'rxjs/Rx';

这使您可以访问完整的 Observable 对象(不仅仅是 Angular 中包含的“Observable-lite”)。这使您能够 .map .reduce 等 Http 请求。

您现在可以在 Http 请求上使用 .map 在服务的上下文中执行任意代码,即使它是订阅结果的组件。因此,为了实现我一开始的目标,我们可以:

service.ts

import { Injectable } from 'angular2/core';    
import { Http } from 'angular2/router';

@Injectable()
export class Service {
    result: Object;

    constructor(http: Http) {
        this.http = http;
    }

    httpGet(url) {
        return this.http.get(url).map(
            result => {
                let data = result.json();
                this.result = data;
                return data
            }
        )
    }
}

组件.ts

import { Component } from 'angular2/core';
import { Service } from './service';

@Component({
    // Component setup
})
export class Component {
    formattedResult: Object;

    constructor(service: Service) {
        this.service = service;
        this.service.httpGet('/api').subscribe(
            data => this.formatResult(data);
        );
    }

    formatResult(result) {
        this.formattedResult = result.map(x => x.length) // For example
    }
}

感谢 Gunter 和 Mark 的回复,帮助我稍微理解了这一点,并且通过阅读大量解决此问题的文档,我觉得我对 Observables 的理解要好得多!

【讨论】:

  • 要包含来自 rxjs 的操作符,请创建文件 rxjs-extensions.ts 并将其包含在您的 polyfils 中,将使用过的操作符的导入添加为 import 'rxjs/operator/map' 等。也永远不要将完整的库导入为 import 'rxjs/Rx' 因为它不是必需的。您可以使用 webpack、angular、js 的不同类型的源地图浏览器检查地图中包含的内容
  • 经过一番挣扎。终于它为我工作了,谢谢伙计。
【解决方案2】:

检查结果是否已经到达,如果是,则创建一个新的 Promise 并用结果完成它,而不是没有,获取它,并将其作为 Promise 返回。

@Injectable()
export class Service {
    result: Object;

    constructor(http: Http) {
        this.http = http;
    }

    httpGet(url) {
        if(result === undefined) {
          return this.http.get(url).toPromise().then(
              result => this.result = result.json(),
              error => console.log(error);
          );
        } else {
          return new Promise().resolve(result);
        }
    }
}

我不知道 TS,这段代码可能包含一些错误(我只使用 Angular 的 Dart),但你应该明白了。

另见
- http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

【讨论】:

  • 好的,很酷,我知道它是如何工作的。将它转换回 Promises 似乎有点可惜,这样你就可以 .then 链接。我希望有一些我不知道的新的可观察的方法。哦,好吧 - 谢谢!
  • 正如我所提到的,我不是 TS 开发人员,但从我看到的其他帖子来看,这似乎是要走的路。
【解决方案3】:

在这种情况下你可以使用回调函数,

举个例子 考虑这是在服务模块中触发 post 服务的 post 函数

postData(id: string, name: string) {
    console.log("Got you",id);
  this._employeeService.postServices({id: id, name: name})
    .subscribe(
      (response:Response) => this.consoleMyOutput(),
      error => console.log(error)
    );  
}

这里注意函数consoleMyOutput()。 这将在服务被调用后得到响应后触发

现在,

consoleMyOutput(){console.log("Write Your call back function")};

此功能将在此之后触发。

【讨论】:

    【解决方案4】:

    这可以通过 Rxjs 方法简单地发生,这是在应用程序加载后调用服务一次的简单而经典的方法,然后我们可以将其订阅到多个组件中。 确保服务对所有组件都是可重用的,所以尽可能多地在服务和地图中编写代码,只在组件中订阅:

    服务

     import { Injectable } from 'angular2/core';    
     import { Http } from 'angular2/http';
    
     @Injectable()
     export class Service {
         result: Object;
    
         constructor(private http: Http) {}
    
         private _urlGet = '/api';
    
         httpGet(){
            return this.http.get(this._urlGet)
              .map(res => JSON.parse(res.json()))
              .do(result => {
                 this.result = result;
               }, error => console.log(error))
         }
      }
    

    组件

     export class Component {
        formattedResult: Object;
    
        constructor(private service: Service) { }
    
        ngOnInit(){
           this.service.httpGet().subscribe(result => {
              this.formattedResult = result;
           }
        }
     }
    

    【讨论】:

      猜你喜欢
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 2013-08-18
      • 2020-01-07
      • 1970-01-01
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多