2017-10-10 1 views
0

Je suis en train d'apprendre Angular 4 et j'ai rencontré un problème auquel je n'arrive pas à trouver de solution. Voici le contexte: J'ai une application simple qui affiche des informations sur les présidents américains. Le backend est une API de repos fournie par webapi ... cela fonctionne très bien. L'extrémité avant est une application Angular.Angulaire 2 - http.get ne jamais être appelé

Ive distillé le problème à 3 composantes, 1 service de données et une modèle. Voici le modèle:

export class President { 
    constructor(
    public id: number, 
    public presidentName: string, 
    public presidentNumber: number, 
    public yearsServed: string, 
    public partyAffiliation: string, 
    public spouse: string) {} 
} 

Les 3 composants sont 1. SearchComponent 2. HomeComponent 3. PresidentComponent

Lorsque l'application bootstraps, il charge le ApplicationComponent - il est le composant racine:

import { Component, ViewEncapsulation } from '@angular/core'; 

@Component({ 
    selector: 'my-app', 
    template: ` 
     <search-component></search-component> 
     <home-component></home-component> 
    ` 
}) 
export class ApplicationComponent {} 

PresidentComponent est un composant enfant de HomeComponent. Lorsque le composant home est chargé, il passe un appel HTTP à l'API pour obtenir une liste des présidents et affiche 1 presidentComponent pour chaque ligne renvoyée. Cela fonctionne bien.

Que Im essayant de faire est de mettre en œuvre une fonction de recherche où le DATASERVICE expose une EventEmitter et fournit la méthode de recherche comme indiqué ici:

import { Injectable, EventEmitter, Output } from '@angular/core' 
import { President } from '../models/President' 

import { Http } from '@angular/http'; 
import 'rxjs/add/operator/toPromise'; 
import 'rxjs/add/operator/map'; 
import { Observable } from 'rxjs/Observable'; 

@Injectable() 
export class DataService { 

    constructor(private http: Http) { 
    } 

    searchEvent: EventEmitter<any> = new EventEmitter(); 

    // simple property for the url to the api 
    get presidentUrl { 
     return "http://localhost:51330/api/presidents"; 
    } 

    search(params: any): Observable<President[]> { 
     let encParams = encodeParams(params); 
     console.log(encParams); 
     return this.http 
      .get(this.presidentUrl, {search: encParams}) 
      .map(response => response.json()); 
    } 


    getParties(): String[] { 
     return ['Republican', 'Democrat', 'Federalist', 'Whig', 'Democratic-Republican', 'None']; 
    } 

    getPresidents(): Observable<President[]> { 
     return this.http.get(this.presidentUrl) 
         .map(response => response.json()); 
    } 

} 

/** 
* Encodes the object into a valid query string. 
* this function is from the book Angular2 Development with TypeScript 
*/ 
function encodeParams(params: any): URLSearchParams { 
    return Object.keys(params) 
     .filter(key => params[key]) 
     .reduce((accum: URLSearchParams, key: string) => { 
     accum.append(key, params[key]); 
     return accum; 
     }, new URLSearchParams()); 
    } 

Les composants de recherche maisons le formulaire de recherche et lorsque le bouton de recherche est cliqué , il exécute la fonction onSearch() et les appels sur le service émette de données:

onSearch(){ 
      if(this.formModel.valid){ 
       console.log('emitting event from search.ts'); 
       this.dataService.searchEvent.emit(this.formModel.value); 
      } 
     } 

Ensuite, dans le HomeComponent, je veux souscrire à cet événement et exécuter une recherche via le dataservice quand il se déclenche:Lorsque j'exécute ceci dans le navigateur, tout fonctionne, sauf que l'appel http n'est jamais exécuté. Si je m'abonne() à l'appel http.get dans le service de données lui-même, il s'exécute mais pourquoi devrais-je le faire quand j'ai un abonnement en cours d'installation sur le HomeComponent? Je souhaite gérer l'Observable dans le composant HomeComponent et mettre à jour la liste des présidents affichés dans l'interface utilisateur en fonction du résultat de la recherche. Tout conseil est grandement apprécié.

+0

@chsdk http://www.typescriptlang.org/docs/handbook/classes.html#accessors – jonrsharpe

Répondre

0

L'idée d'utiliser toute EventEmitter au service est pas juste. EventEmitter doit être utilisé avec les propriétés @Output pour envoyer des données du composant enfant à son parent.

Même si le EventEmitter est une sous-classe du sujet, vous ne devriez pas l'utiliser dans les services. Donc, injectez le service dans votre composant, abonnez-vous à son observable dans le composant, et émettez un événement en utilisant EventEmitter au composant parent si besoin est.

+0

Merci pour les conseils sur ne pas utiliser EventEmitters dans les services. C'est malheureux que j'ai trouvé cette méthode utilisée dans le livre que j'ai référencé dans mon post. encore – Alex

+0

Regardez cette vidéo: https://www.youtube.com/watch?v=NYNEH_k0e_4 - Je montre comment utiliser un sujet de comportement dans un service. –

0

Dans le code this.result = this.dataService.search(params);, le résultat est observable. Vous n'avez pas fait d'abonnement.

Dans ce cas, vous devriez avoir utilisé le tuyau async pour afficher les données.

0

Pourquoi ne pas utiliser Subject de rxjs.Voici ce que je propose:

DataService:

import { Observable, Subject } from "rxjs"; 
import 'rxjs/add/operator/catch'; 

@Injectable() 
export class DataService { 
    private _dataSubject = new Subject(); 

    constructor(private http: Http) { 
     this.http.get(this.presidentUrl) 
     .map(response => this._dataSubject.next(response.json())) 
     .catch(err => this._dataSubject.error(err));   
     ); 
    } 

// simple property for the url to the api 
get presidentUrl { 
    return "http://localhost:51330/api/presidents"; 
} 

search(params: any){ 
    let encParams = encodeParams(params); 
    console.log(encParams); 
    this.http 
     .get(this.presidentUrl, {search: encParams}) 
     .map(response => this._dataSubject.next(response.json())) 
     .catch(err => this._dataSubject.error(err)); 
} 


getParties(): String[] { 
    return ['Republican', 'Democrat', 'Federalist', 'Whig', 'Democratic-Republican', 'None']; 
} 

getPresidents(): Observable<President[]> { 
    return this._dataSubject; 
} 

SearchComponent:

onSearch(){ 
     if(this.formModel.valid){ 
      console.log('emitting event from search.ts'); 
      this.dataService.search(this.formModel.value); 
     } 
    } 

Avec ces modifications, vous devriez être en mesure d'avoir seulement 1 abonné homeCompoent et obtenir de nouvelles données émises chaque l'heure onSearch() est appelée.