在构造函数

时间:2018-01-25 04:18:09

标签: angular typescript asynchronous

我正在使用对我的Web API的HTTP调用来检索2个API密钥以使用另一个API。

通过2个函数检索这些API密钥: getApiKey()getAppId()

当我在构造函数中调用这些函数时,它们返回的值(全局变量)是未定义的。

当我在构造函数之外调用它时,它工作正常。

我不想使用全局变量,但是当我尝试在getApiKey()getAppid()函数体内创建变量并将其分配到http.get调用中时,它也会返回undefined

我猜这与http.get异步有关,但我不知道如何解决它/如何让它等待响应。

这是我的代码:

import { Component, OnInit } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Constants } from '../../utils/constants';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-recipes',
  templateUrl: './recipes.component.html',
  styleUrls: ['./recipes.component.css']
})
export class RecipesComponent {
  appid;  
  appkey;
  matchesList;  
  recipeSearchForm: FormGroup;
  notFoundError: boolean = false;

  constructor(private http: Http) {
    this.searchRecipeInit();    //undefined here

    this.recipeSearchForm = new FormGroup({
      recipeSearchInput: new FormControl()
    });
  }

  getApiKey(){
    this.http.get(Constants.GET_YUMMLY_APP_KEY, this.getOptionsSimple()).subscribe((res: Response) => {  
      this.appkey = res.text();
      console.log(this.appkey);   
    });
    return this.appkey;    
  }

  getAppId(){
    this.http.get(Constants.GET_YUMMLY_APP_ID, this.getOptionsSimple()).subscribe((res: Response) => {  
      this.appid = res.text(); 
      console.log(this.appid);      
    });
    return this.appid;    
  } 

  getSearchParams(){
    // get from search text field
    var str = this.recipeSearchForm.get('recipeSearchInput').value
    // split into words and add + in between
    if(str != null) {
      var correctFormat = str.split(' ').join('+');
      return correctFormat          
    }
    return str
  }

  getOptions(){
    var headers = new Headers();

    headers.append('Content-Type', 'application/json' );    
    headers.append('X-Yummly-App-Key',this.getApiKey());    
    headers.append('X-Yummly-App-ID',this.getAppId());

    let options = new RequestOptions({ headers: headers });

    return options;
  }

  getOptionsSimple(){
    var headers = new Headers();

    headers.append('Content-Type', 'application/json' ); 

    let options = new RequestOptions({ headers: headers });

    return options;
  }

  searchRecipe() {     
      // not undefined here
      this.http.get(Constants.GET_SEARCH_RECIPE+this.getSearchParams(), this.getOptions()).subscribe((res: Response) => {  
        this.matchesList = res.json().matches;

        console.log(this.matchesList);
        if(this.matchesList.length == 0){
          this.notFoundError = true;
        }
        else{
          this.notFoundError = false;
        }
      },
      (err) => {
        if(err.status == 400){
          // Bad Request
        }
        else if(err.status == 409){
          // API Rate Limit Exceeded
        }
        else if(err.status == 500){
          // Internal Server Error
        }
      });
  }

  searchRecipeInit() {     
    this.http.get(Constants.GET_SEARCH_RECIPE+"", this.getOptions()).subscribe((res: Response) => {  
      this.matchesList = res.json().matches;

      this.notFoundError = false;      
    },
    (err) => {
      if(err.status == 400){
        // Bad Request
      }
      else if(err.status == 409){
        // API Rate Limit Exceeded
      }
      else if(err.status == 500){
        // Internal Server Error
      }
    });
}
}

1 个答案:

答案 0 :(得分:1)

您包含的代码按预期工作。这个问题可能与How do I return the response from an asynchronous call? 重复,但由于它更多是关于可观察的,我会回答它。

您对异步代码的误解是主要问题,特别是代码如下

getAppId() {
    this.http.get(Constants.GET_YUMMLY_APP_ID, this.getOptionsSimple()) // 1
        .subscribe((res: Response) => {                                 // 
            this.appid = res.text();                                    // 3
            console.log(this.appid);                                    // 4
        });
    return this.appid;                                                  // 2
} 

代码按照右侧标记的编号顺序执行。由于TypeScript / JavaScript是同步的,它将触发http.get(...)函数,然后继续到下一行,在本例中为return this.appid;this.appid目前有什么价值? undefined,因此它按预期工作。

您必须返回http.get(...)的结果,该结果在调用.subscribe()函数之前不可用。

由于您依赖于两个单独的http.get(...)来电,一个用于apiKey,一个用于appId,因此您可以利用Rx运算符来“等待”它们完成/发出值。在这种情况下,想到的是Observable.zip()函数。

我已经创建了一个代码段,可以指导您按正确的方向让代码按预期运行。

class SearchRecipeDemo {

  private getAppId() {
    return this.http.get(Constants.GET_YUMMLY_APP_ID);
  }

  private getApiKey() {
    return this.http.get(Constants.GET_YUMMLY_APP_KEY);
  }

  private init(): void {
    this.searchRecipe();
  }

  private getOptions() {
    return Rx.Observable.zip(getApiKey(), getAppId()).map((result) => {
        // Prints your keys
        console.log(`apiKey: ${result[0].text()}`);
        console.log(`appId: ${result[1].text()}`);

        // Create the RequestOptions
        let headers = new Headers();

        headers.append('Content-Type', 'application/json');
        headers.append('X-Yummly-App-Key', result[0].text());
        headers.append('X-Yummly-App-ID', result[1].text();

          const options = new RequestOptions({
            headers: headers
          });
          return options;
        });
    });

  private searchRecipe() {
    this.getOptions().map((options) => {
        // Options here is the RequestOptions object returned from the 'getOptions' function
        console.log(options);

        //Make your request to search the recipe here
      })
      .subscribe();
  }
}

new SearchRecipeDemo().init();

在这个JSBin JSBin片段中查看一个稍微不同的代码版本,该代码段模拟了observable。

相关问题