Angular 6 - HttpClient Сохранение подписки в сервисе, но передача результата компоненту - PullRequest
0 голосов
/ 28 мая 2018

У меня есть объект, который содержит службу (которая получает данные) и компонент (отображает его).

Я хотел бы сохранить минимальный код на 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();
  }

Итак, мой вопрос, как я могу это сделать, или действительно рекомендуется вызывать подписку на моем компоненте, а не в службе?

Ответы [ 4 ]

0 голосов
/ 28 мая 2018

В новых HttpClientModule JSON является предполагаемым значением по умолчанию и больше не нуждается в явном разборе с использованием res.json()

Вы можете сказать HttpClientтип ответа, чтобы сделать использование вывода более простым и очевидным.

Проверка типа ответа может быть выполнена с помощью параметра типа
Создание интерфейса

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

Http возвращает observable, и мы можем указать HttpClient.get вернуть response в качестве типа Idata. Когда мы используем 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');
    }
}

В вашем компоненте subscribe до Observable<Idata[]> для получения экземпляра Idata

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

Альтернатива - Использование async pipe AsyncPipe принимает в качестве аргумента observable или promise, вызывает 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

У меня вопрос, как я могу это сделать, или действительно рекомендуется звонить по подписке на мой компонент, а не на сервис?

Это хорошая практикаДелегировать сложную логику компонента сервисам

С Angular Style Guide
Ограничивать логику в компоненте только той, которая требуется для представления.Вся остальная логика должна быть делегирована сервисам.

Перемещать многократно используемую логику в сервисы и сохранять компоненты простыми и ориентированными на их предназначение.

Почему?Логика может быть повторно использована несколькими компонентами, если она размещена внутри службы и доступна через функцию.

Почему?Логика в сервисе может быть легче изолирована в модульном тесте, тогда как логика вызова в компоненте может быть легко смоделирована.

Почему?Удаляет зависимости и скрывает детали реализации от компонента.

Почему?Делает компонент тонким, аккуратным и сфокусированным.

Подписка в компоненте позволяет вам совместно использовать один запрос http с несколькими observers, если вы этого не сделаете, вы нарушите DRY Принцип
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, который создает подписку, когда число наблюдателей уменьшается с нуля до одного, а затем делится этой подпиской со всемипоследующие наблюдатели до тех пор, пока количество наблюдателей не вернется к нулю, после чего подписка будет ликвидирована.

0 голосов
/ 28 мая 2018

Ваш component.ts должен быть таким.

Нет проблем в вашем сервисе, кроме подписки должна быть карта.

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

    setMyData() {
        this.myData = data;
    }
0 голосов
/ 28 мая 2018

Отлично!Вы можете попробовать с 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)

Попробуйте и посмотрите, сработало ли!Я надеюсь, что это помогает!

0 голосов
/ 28 мая 2018

Если вы хотите использовать сервисные методы, вы должны вернуть наблюдаемый ответ, подобный следующему:

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