2017-10-10 97 views
0

我在学习Angular 4并遇到了一个我似乎无法找到解决方案的问题。这里是背景: 我有一个简单的应用程序,显示有关美国总统的信息。 后端是由webapi提供的其余API ...这工作正常。 前端是一个Angular应用程序。Angular 2 - http.get永远不会打电话

我将问题简化为3个组件,1个数据服务和1个模型。 这里是模型:

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

的3个组分是 1.的SearchComponent 2. HomeComponent 3. PresidentComponent

当应用程序自举时,它加载ApplicationComponent - 它是根组件:

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

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

PresidentComponent是HomeComponent的子组件。加载home组件时,它会对api进行http调用以获取总统列表,并为返回的每一行呈现1个presidentComponent。这工作正常。

什么即时试图做的是实现搜索功能,其中DataService在暴露的EventEmitter并提供搜索方法如下所示:

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

搜索组件的房屋搜索表单,并点击搜索按钮时,它执行onSearch()函数,并调用数据服务发出:

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

然后,在HomeComponent,我想订阅此事件,并通过DataService在执行搜索时,它触发:

ngOnInit(): void { 
     //when component loads, get list of presidents 
     this.dataService.getPresidents() 
     .subscribe(
      presidents => { 
       console.log('sub'); 
       this.presidents = presidents; 

      }, 
      error => console.error(error) 
     ) 

    //when search event is fired, do a search 
    this.dataService.searchEvent 
     .subscribe(
      params => { 
       console.log('in home.ts subscribe ' + JSON.stringify(params)); 
       this.result = this.dataService.search(params); 
      }, 
      err => console.log("cant get presidents. error code: %s, URL: %s"), 
      () => console.log('done') 
     ); 
    } 

当我在浏览器中运行它时,除了http调用以外的所有工作都不会执行。如果我在数据服务本身中订阅()到http.get调用,它会执行,但为什么我必须在HomeComponent上设置订阅时这样做? 我想处理HomeComponent中的Observable,并根据搜索结果更新UI中显示的总统列表。 任何意见,不胜感激。

+0

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

回答

0

在服务中使用EventEmitter的整个想法是不正确的。 EventEmitter应与@Output属性一起使用,以便将数据从子组件发送到其父组件。

即使EventEmitter是Subject的子类,您也不应该在服务中使用它。因此,将服务注入组件,订阅组件中的observable,并在需要时使用EventEmitter向父组件发送事件。

+0

感谢关于在服务中不使用EventEmitter的指导。不幸的是,我发现我在文章中引用的书中使用的方法。 thx再 – Alex

+0

观看此视频:https://www.youtube.com/watch?v=NYNEH_k0e_4 - 我展示了如何在服务中使用行为主题。 –

0

在代码this.result = this.dataService.search(params);中,结果是可观察的。你还没有订阅。

在这种情况下,您应该使用async管道来显示数据。

0

为什么不使用Subjectrxjs。这里是我的建议:

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

有了这些修改,你应该能只有1个用户在homeCompoent,然后让每个发出的新数据时间onSearch()被调用。