angular/ts在异步调用中分配的全局变量在构造函数中未定义
我正在使用对Web API的HTTP调用来检索2个API键以使用另一个API 通过2个函数检索这些API密钥: getApiKey和getAppId 当我在构造函数中调用这些函数时,它们返回的值(一个全局变量)是未定义的 当我在构造函数外部调用它时,它工作得很好 我不想使用全局变量,但当我尝试在getApiKey或getAppid函数体中创建变量并在http.get调用中赋值时,它也会返回未定义的变量 我猜这与http.get是异步的有关,但我不知道如何修复它/如何让它等待响应 这是我的密码:angular/ts在异步调用中分配的全局变量在构造函数中未定义,angular,typescript,asynchronous,Angular,Typescript,Asynchronous,我正在使用对Web API的HTTP调用来检索2个API键以使用另一个API 通过2个函数检索这些API密钥: getApiKey和getAppId 当我在构造函数中调用这些函数时,它们返回的值(一个全局变量)是未定义的 当我在构造函数外部调用它时,它工作得很好 我不想使用全局变量,但当我尝试在getApiKey或getAppid函数体中创建变量并在http.get调用中赋值时,它也会返回未定义的变量 我猜这与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
}
});
}
}
您包含的代码按预期工作。这个问题可能是重复的,但因为它更多的是关于可观测的,所以我会回答它 您对异步代码的误解是主要的问题,特别是像下面这样的代码
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。。。函数,然后继续下一行,在本例中是返回this.appid;。此时this.appid的值是多少?未定义,因此它按预期工作
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();
您必须返回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代码片段中模拟可观察对象的代码的一个稍微不同的版本。谢谢您的详细回复!我了解其中的大部分内容,唯一一件我仍然不太明白的事情是,在这种情况下,我应该如何将我的appkey和appid绑定到http调用的响应。我是否在getOptions正文中进行http调用?我已使用稍微不同的代码段更新了我的答案,该代码段与您的应用程序更匹配。我用对getApiKey和getAppId函数的调用替换了模拟的观察值。注意,我还更改了这些函数,以从http.get调用返回可观察的。我真的搞不懂为什么要使用GetOptionSimple,所以我略去并重构了代码。