typescript Angular 6 - HttpClient 保持订阅服务但将结果传递给组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50570340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:26:59  来源:igfitidea点击:

Angular 6 - HttpClient Keeping subscribe in the service but passing the result to the component

angulartypescriptangular6angular-httpclient

提问by

I have a preject which contains a service (which gets the data) and a component (displays it).

我有一个包含服务(获取数据)和组件(显示它)的项目。

I would like the keep the code to the minimum on the app.component.ts.

我希望将 app.component.ts 上的代码保持在最低限度。

In the service I have:

在服务中,我有:

getPosts() {
    return this.http.get('https://jsonplaceholder.typicode.com/posts', httpOptions).subscribe(
      result => {
        return result;
        this.theData = result;
      },
      error => {
        return error;
      }
    );
  }

and in my app.component.ts:

在我的 app.component.ts 中:

 getPostsFromService() {
    this.myService.getPosts();
  }

But of course, I need to get the result and pass it into my component but something like this wouldn't work:

但是,当然,我需要获取结果并将其传递到我的组件中,但是这样的事情是行不通的:

myData;

  ...


  getPostsFromService() {
    this.myData = this.myService.getPosts();
  }

So, my question is, how can I do this or is it really recommended to call subscribe on my component and not in the service?

所以,我的问题是,我该怎么做,还是真的建议在我的组件上调用 subscribe 而不是在服务中调用?

采纳答案by Vikas

In new HttpClientModuleJSON is an assumed default and no longer needs to be explicitly parsed using res.json()

在新的HttpClientModule 中,JSON 是假定的默认值,不再需要使用显式解析res.json()

You can tell HttpClientthe type of the response to make consuming the output easier and more obvious.

您可以告诉HttpClient响应的类型,以便更轻松、更明显地使用输出。

Type checking of response can be done by using the type parameter
Create an Interface

响应的类型检查可以通过使用类型参数
Create an Interface来完成

export interface Idata{
  userId:number;
  Id:number;
  title:string;
  body:string;
}

Httpreturns an observableand We can tell the HttpClient.getto return responseas Idata type When we use http.get<Idata[]>(...)then it returns the instance of Observable<Idata[]>type.
In your service

Http返回一个observableand 我们可以告诉HttpClient.get返回response为 Idata 类型 当我们使用http.get<Idata[]>(...)then 它返回Observable<Idata[]>类型的实例。
为您服务

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {Observable} from 'rxjs';
import {Idata} from './Idata'
@Injectable()
export class ShareService {

    constructor(private httpc:HttpClient)
    {
    }

    public getPosts():Observable<Idata[]>
    {
        return this.httpc.get<Idata[]>('https://jsonplaceholder.typicode.com/posts');
    }
}

In your component subscribeto Observable<Idata[]>to get instance of Idata

在您的组件subscribeObservable<Idata[]>获取 Idata 的实例

  public data:Array<Idata>=[];
  constructor(public service:ShareService)
  {
     this.service.getPosts().subscribe(value => {
        this.data=value;
     });
  }

An alternative is Using asyncpipe AsyncPipeaccepts as an argument an observableor a promise, calls subscribeor attaches a then handler, then waits for the asynchronous result before passing it through to the caller.

另一种方法是使用async管道 AsyncPipe接受 anobservable或 a作为参数promise,调用subscribe或附加 then 处理程序,然后在将异步结果传递给调用者之前等待异步结果。

public response:Observable<Idata[]>;
constructor(public service:ShareService)
{
    this.response=this.service.getPosts();
}

HTML

HTML

<div *ngFor="let item of (response|async)">
  {{item.body}}
</div>


LIVEDEMO


现场演示

my question is, how can I do this or is it really recommended to call subscribe on my component and not in the service?

我的问题是,我该怎么做,还是真的建议在我的组件上调用 subscribe 而不是在服务中?

It's Good Practice to Delegate complex component logic to services

将复杂的组件逻辑委托给服务是一种很好的做法

From Angular Style Guide
Do limit logic in a component to only that required for the view. All other logic should be delegated to services.

Do move reusable logic to services and keep components simple and focused on their intended purpose.

Why? Logic may be reused by multiple components when placed within a service and exposed via a function.

Why? Logic in a service can more easily be isolated in a unit test, while the calling logic in the component can be easily mocked.

Why? Removes dependencies and hides implementation details from the component.

Why? Keeps the component slim, trim, and focused.

来自Angular Style Guide
将组件中的逻辑限制为视图所需的逻辑。所有其他逻辑都应该委托给服务。

务必将可重用逻辑移至服务并保持组件简单并专注于其预期目的。

为什么?当逻辑被放置在一个服务中并通过一个函数公开时,它可以被多个组件重用。

为什么?在单元测试中可以更轻松地隔离服务中的逻辑,而可以轻松模拟组件中的调用逻辑。

为什么?删除依赖项并隐藏组件的实现细节。

为什么?保持组件纤薄、修剪和集中。

Subscribing in Component lets you share a single httprequest with multiple observers, if you don't do so you would be violating DRY Principle
P:STo share a single httprequest for multiple observers, you need something like the shareoperator.

在 Component 中订阅允许您http与多个共享单个请求observers,如果您不这样做,您将违反DRY 原则
P:Shttp为多个共享单个请求observers,您需要类似share运算符的东西。

import {Observable} from 'rxjs';
import {share} from 'rxjs/operators'

export class dataService {

    public data$=Observable<Idata[]>
    constructor(http:HttpClient)
    {
        this.data$=this.http.get<Idata[]>('https://jsonplaceholder.typicode.com/posts').pipe(share());
    }
    public getPosts():Observable<Idata[]>
    {
        return this.data$
    }
}

This operator is a specialization of publishwhich creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.

该运算符是一种特殊化,publish当观察者的数量从零变为 1 时,它会创建一个订阅,然后与所有后续观察者共享该订阅,直到观察者的数量归零,此时订阅将被处理。

回答by Chiien

Great! You can try with Observable and Async! In app.component

伟大的!您可以尝试使用 Observable 和 Async!在 app.component

public posts: Observable<posts[]>
getPostsFromService() {
  this.posts = this.myService.getPosts();
}

And in html, you put that:

在 html 中,您输入:

*ngFor="let post of posts | async"

And service

和服务

return this._http.get<posts>('https://jsonplaceholder.typicode.com/posts', httpOptions)

Try that and see if worked! I hope that helps!

试试看,看看是否有效!我希望这有帮助!

回答by OPV

If you desire to use a service methods must return observable response like this:

如果您希望使用服务方法,则必须像这样返回可观察的响应:

public getPosts(): Observable<IPosts[]> {

    const data = {
      '$type' : 'ReadRequest',
      'query' : 'getPosts',
      'parameters' : {}
    };

    return this.http.post(null, data)
      .map(res => (<any>res)._body === '' ? {} : res.json().result)
      .catch(this.handleError);
  }

  private handleError(error: any): Promise<any> {
    return Promise.reject(error.message || 'Server error: ' + error);
  }

Where IPostsis described Interface according your response.

IPosts根据您的回复描述的接口在哪里。

After in any component you can use this:

在任何组件之后,您都可以使用它:

public posts: IPosts[] = [];
this.servicePosts.getPosts().subscribe(data => {
       this.posts = data; // Fill data from response to component variable this.post
          }, error => {
            console.log(error);
          });

回答by Padmapriya Vishnuvardhan

Your component.ts should be like this.

你的 component.ts 应该是这样的。

There is no issue in your service except subscribe should be map.

除了订阅应该是地图之外,您的服务没有问题。

 this.myService.getPosts().subscribe((data) => {
         this.setMyData(data);
    });

    setMyData() {
        this.myData = data;
    }