【问题标题】:Angular 2 - http.get never being callAngular 2 - http.get 永远不会被调用
【发布时间】:2017-10-11 01:14:21
【问题描述】:

我正在学习 Angular 4,但遇到了一个我似乎找不到解决方案的问题。这是上下文: 我有一个简单的应用程序,显示有关美国总统的信息。 后端是 webapi 提供的一个 rest API ......这工作正常。 前端是一个 Angular 应用程序。

我已将问题简化为 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) {}
}

这三个组成部分是 1. 搜索组件 2. HomeComponent 3.总裁组件

当应用启动时,它会加载 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 个总裁组件。这很好用。

我想做的是实现一个搜索功能,其中 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() 函数并在数据服务上调用 emit:

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

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

 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 调用永远不会执行。如果我 subscribe() 到数据服务本身中的 http.get 调用,它会执行,但是当我在 HomeComponent 上设置订阅时,为什么我必须这样做? 我想处理 HomeComponent 中的 Observable 并根据搜索结果更新 UI 中显示的总统列表。 非常感谢任何建议。

【问题讨论】:

标签: javascript angular observable


【解决方案1】:

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

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

【讨论】:

  • 感谢关于不在服务中使用 EventEmitters 的指导。不幸的是,我发现我在帖子中引用的书中使用的方法。再次感谢
  • 观看此视频:youtube.com/watch?v=NYNEH_k0e_4 - 我展示了如何在服务中使用行为主题。
【解决方案2】:

在代码this.result = this.dataService.search(params); 中,结果是一个可观察的。您尚未订阅。

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

【讨论】:

    【解决方案3】:

    为什么不使用rxjs 中的Subject。这是我的建议:

    数据服务:

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

    搜索组件:

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

    通过这些修改,您应该能够在 homeCompoent 中只有 1 个订阅者,然后每次调用 onSearch() 时都会发出新数据。

    【讨论】:

      猜你喜欢
      • 2018-05-30
      • 2012-10-27
      • 2013-10-12
      • 2012-03-27
      • 2013-08-29
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      相关资源
      最近更新 更多