【问题标题】:Angular 6 - HttpClient Keeping subscribe in the service but passing the result to the componentAngular 6 - HttpClient 保持订阅服务但将结果传递给组件
【发布时间】:2018-11-07 06:45:42
【问题描述】:

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

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

在我拥有的服务中:

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

在我的 app.component.ts 中:

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

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

myData;

  ...


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

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

【问题讨论】:

    标签: angular typescript angular6 angular-httpclient


    【解决方案1】:

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

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

    可以使用 type 参数对响应进行类型检查
    创建接口

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

    Http 返回一个observable,我们可以告诉HttpClient.get 以Idata 类型返回response 当我们使用http.get<Idata[]>(...) 时,它返回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');
        }
    }
    

    在您的组件中 subscribeObservable&lt;Idata[]&gt; 以获取 Idata 实例

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

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

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

    HTML

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


    LIVEDEMO

    我的问题是,我该怎么做,或者真的建议打电话 订阅我的组件而不是服务?

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

    来自 Angular 样式指南
    将组件中的逻辑限制为仅 视图所需的。所有其他逻辑应委托给 服务。

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

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

    为什么?服务中的逻辑可以更容易地在单元测试中隔离, 而组件中的调用逻辑很容易被mock。

    为什么?从 组件。

    为什么?使组件保持苗条、修剪和集中。

    在组件中订阅可以让您与多个 observers 共享一个 http 请求,如果您不这样做,您将违反 DRY Principle
    P: S 要共享单个 http 请求多个 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$
        }
    }
    

    这个操作符是publish 的特化,它创建了一个 当观察者的数量从零变为一时订阅,然后 与所有后续观察者共享该订阅,直到 观察者数量归零,此时订阅 被处理掉了。

    【讨论】:

      【解决方案2】:

      太棒了!你可以试试 Observable 和 Async! 在 app.component 中

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

      在 html 中,你这样写:

      *ngFor="let post of posts | async"
      

      还有服务

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

      试试看是否有效!希望对您有所帮助!

      【讨论】:

        【解决方案3】:

        如果您希望使用服务方法,则必须返回可观察到的响应,如下所示:

        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);
          }
        

        IPosts 是根据您的回复描述的接口。

        在任何组件之后你都可以使用这个:

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

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

          • 我可以知道投反对票的原因,以便我更正自己。
          • 你想通过这段代码实现什么?问题是如何解决服务层本身的响应并将数据返回给组件。希望你根本没有得到这个问题。此外,您的代码有 setMyData() 没有将数据作为输入读取的错误。
          猜你喜欢
          • 1970-01-01
          • 2017-09-19
          • 2019-09-10
          • 1970-01-01
          • 1970-01-01
          • 2018-10-11
          • 1970-01-01
          • 1970-01-01
          • 2018-03-30
          相关资源
          最近更新 更多