简体   繁体   English

Angular 2-永远不会被http.get调用

[英]Angular 2 - http.get never being call

Im learning Angular 4 and have run into a problem that I cannot seem to find a solution to. 我正在学习Angular 4,遇到了一个我似乎找不到解决方案的问题。 Here is the context: I have a simple app that displays info about US Presidents. 这里是上下文:我有一个简单的应用程序,显示有关美国总统的信息。 The backend is a rest API provided by webapi...this works fine. 后端是webapi提供的rest API ...效果很好。 The front end is an Angular app. 前端是一个Angular应用程序。

Ive distilled the problem down to 3 components, 1 data service and 1 model. 我将问题简化为3个组件,1个数据服务和1个模型。 Here is the model: 这是模型:

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

The 3 components are 1. SearchComponent 2. HomeComponent 3. PresidentComponent 这三个组件是1. SearchComponent 2. HomeComponent 3. PresidentComponent

When the app bootstraps, it loads the ApplicationComponent - it is the root component: 当应用程序启动时,它将加载ApplicationComponent-它是根组件:

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

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

PresidentComponent is a child component of HomeComponent. PresidentComponent是HomeComponent的子组件。 When home component loads, it makes an http call to the api to get a list of presidents and renders 1 presidentComponent for each row returned. 加载home组件时,它将对api进行http调用以获取总裁列表,并为返回的每一行呈现1 PresidentComponent。 This works fine. 这很好。

What Im trying to do is implement a search feature where the dataService exposes an EventEmitter and provides the search method as shown here: 我想做的是实现一个搜索功能,其中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());
  }

The Search Component houses the search form and when the search button is clicked, it executes the onSearch() function and calls emit on the data service: 搜索组件包含搜索表单,当单击搜索按钮时,它将执行onSearch()函数并在数据服务上发出调用:

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

Then, in the HomeComponent, I want to subscribe to this event and execute a search via the dataservice when it fires: 然后,在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')
        );
    }

When I run this in the browser, everything works except the http call is never executed. 当我在浏览器中运行此命令时,除http调用外,其他所有功能都不会执行。 If I subscribe() to the http.get call in the dataservice itself, it executes but why should I have to do that when I have a subscription being setup on the HomeComponent? 如果我对dataservice本身中的http.get调用执行subscription(),它将执行,但是为什么要在HomeComponent上设置订阅时为什么要这样做呢? I want to handle the Observable in the HomeComponent and update the list of presidents that is being displayed in the UI based on the search result. 我想在HomeComponent中处理Observable,并根据搜索结果更新UI中显示的行长列表。 Any advice is greatly appreciated. 任何意见是极大的赞赏。

The entire idea of using EventEmitter in the service is not right. 在服务中使用EventEmitter的整个想法是不正确的。 The EventEmitter should be used with @Output properties to send data from the child component to its parent. EventEmitter应该与@Output属性一起使用,以将数据从子组件发送到其父组件。

Even though the EventEmitter is a subclass of the Subject, you shouldn't be using it in services. 即使EventEmitter是Subject的子类,您也不应该在服务中使用它。 So inject the service into your component, subscribe to its observable in the component, and emit an event using EventEmitter to the parent component if need be. 因此,将服务注入您的组件,订阅其​​在组件中的可观察对象,并在需要时使用EventEmitter向父组件发出事件。

In the code this.result = this.dataService.search(params); 在代码中this.result = this.dataService.search(params); , result is an observable. ,结果是可观察的。 You have not made a subscription. 您尚未订阅。

In that case you should have used the async pipe to display the data. 在这种情况下,您应该使用async管道来显示数据。

Why not use Subject from rxjs . 为什么不使用rxjs Subject Here is what i am proposing: 这是我的建议:

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: SearchComponent:

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

With these modifications you should be able to have only 1 subscriber in homeCompoent and then get new data emitted every time onSearch() is called. 通过这些修改,您应该只能在homeCompoent中只有1个订阅者,然后每次调用onSearch()onSearch()获取发出的新数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM