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?
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 async
AsyncPipe
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>
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é.
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!
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);
}
Où 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);
});