web-dev-qa-db-fra.com

Angular 6 - HttpClient Conserver son abonnement au service mais transmettre le résultat au composant

J'ai un preject qui contient un service (qui récupère les données) et un composant (l'affiche).

Je voudrais le garder le code au minimum sur le app.component.ts.

Dans le service j'ai:

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

et dans mon app.component.ts:

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

Mais bien sûr, je dois obtenir le résultat et le transmettre à mon composant, mais cela ne fonctionnerait pas:

myData;

  ...


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

Ma question est donc la suivante: comment puis-je faire cela ou est-il vraiment recommandé d'appeler s'abonner à mon composant et non au service?

6
MarkHill2018

Dans la nouvelle HttpClientModule, JSON est une valeur par défaut supposée et ne doit plus être explicitement analysé à l'aide de res.json().

Vous pouvez indiquer à HttpClient le type de réponse afin de rendre la consommation de la sortie plus facile et plus évidente.

La vérification du type de réponse peut être effectuée à l'aide du paramètre type
Créer une interface

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

Http renvoie observable et nous pouvons indiquer au HttpClient.get de renvoyer response en tant que type Idata. Lorsque nous utilisons http.get<Idata[]>(...), il renvoie ensuite l'instance de type Observable<Idata[]>
À votre service 
 

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

Dans votre composant subscribe à Observable<Idata[]> pour obtenir une instance d'Idata

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

Une alternative consiste à utiliser le tube asyncAsyncPipe accepte comme argument une variable observable ou promise, appelle subscribe ou attache un gestionnaire then, puis attend le résultat asynchrone avant de le transmettre à l'appelant.

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

HTML

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


V&EACUTE;CUEMO

ma question est, comment puis-je faire cela ou est-il vraiment recommandé d'appeler souscrire sur mon composant et non dans le service?

Il est de bonne pratique de déléguer la logique de composant complexe aux services

De Guide de style angulaire
Limitez la logique dans un composant à seulement que nécessaire pour la vue. Toute autre logique doit être déléguée à prestations de service.

Déplacez la logique réutilisable vers les services et gardez les composants simples et axé sur leur objectif.

Pourquoi? La logique peut être réutilisée par plusieurs composants lorsqu'elle est placée dans un service et exposé via une fonction.

Pourquoi? La logique dans un service peut plus facilement être isolée dans un test unitaire, tandis que la logique d'appel dans le composant peut être facilement moquée.

Pourquoi? Supprime les dépendances et masque les détails d'implémentation du fichier composant.

Pourquoi? Maintient le composant mince, soigné et concentré.

S'abonner à Component vous permet de partager une seule requête http avec plusieurs observers. Sinon, vous violeriez le principe DRY.
P: S Pour partager une seule requête http pour plusieurs observers, vous avez besoin de quelque chose comme l'opérateur 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$
    }
}

Cet opérateur est une spécialisation de publish qui crée un abonnement lorsque le nombre d’observateurs passe de zéro à un, puis partages avec tous les observateurs suivants jusqu'au le nombre d'observateurs revient à zéro, date à laquelle l'abonnement est disposé.

4
Vikas

Génial! Vous pouvez essayer avec Observable et Async! Dans app.component

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

Et en html, vous mettez ça:

*ngFor="let post of posts | async"

Et service

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

Essayez ça et voyez si ça marche! J'espère que ça aide!

1
Chiien

Si vous souhaitez utiliser un service, les méthodes doivent renvoyer une réponse observable comme ceci:

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 est décrit Interface en fonction de votre réponse.

Après dans n'importe quel composant, vous pouvez utiliser ceci:

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