我正在使用对我的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
}
});
}
}
答案 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。