Angular“无法读取未定义的属性‘subscribe’”
在开始问题之前,我想让您知道我已经进行了大型研究,我找不到解决方案(说明)为什么我会遇到此错误。
也请注意,我完全是Angular的新手,我才开始学习它的工作原理。
所以,我的问题是我在这个问题的标题中输入的问题。
我尝试做的是根据我在Udemy上购买的课程来构建登录系统。
我使用的代码如下:
auth.service.ts
786912877
data-storage.service.ts
921717467
header.component.ts
638324424
因此,不幸的是,我看不到此代码可能有什么问题。谁能发现我做错了什么?
注意: 我删除了代码的一部分只是为了使片段更可读。如果您需要其他任何部分,请随时问我,我将在此处提供。
更新#1
这就是<代码> header.component.html
575821032
我使用未初始化的 EventEmitter 时遇到了同样的错误:
@Output() change: EventEmitter<any>;
而不是:
@Output() change: EventEmitter<any> = new EventEmitter<any>();
错误发生在尝试订阅更改事件的更高级别组件中。
问题似乎出在代码执行的顺序上,更具体地说是
getRecipes()
方法:
// Numbers indicate the execution order
getRecipes () {
const token = this.authService.getToken ();
// 1. You call a promise, which will take a while to execute...
token.then (
( token: string ) => {
// 3. Finally, this bit gets executed, but only when the promise resolves.
this.recipeSubscription = ...
}
);
// 2. Then, you return a variable that hasn't been assigned yet,
// due to the async nature of the promise.
return this.recipeSubscription;
}
解决方案是,您的
getRecipes ()
方法不应订阅。它应该
返回 Promise 或 Observable
。
类似这样:
getRecipes() {
// Convert the initial promise into an observable
// so can you use operators like map(), mergeMap()... to transform it.
const tokenObs = Observable.fromPromise(this.authService.getToken());
// Merge the token observable into an HTTP observable
// and return the JSON data from the response.
return tokenObs
.mergeMap(token => this.http.get('XXX?auth=' + token))
.map(resp => resp.json());
}
然后,
HeaderComponent
中的调用代码变为:
const recipeObs = this.dataStorage.getRecipes();
recipesObs.subcribe(jsonData => {
// Use the JSON data from the HTTP response
});
几点说明:
- 您需要明确导入代码中使用的 RxJS 运算符。如果您按照我的示例操作,则需要在开头添加以下导入:
import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
-
您永远不应该在创建可观察对象的方法中进行订阅。就您而言,请不要在
getRecipes()
中进行订阅。始终尽可能在最后一刻进行订阅。您可以多次订阅同一个可观察对象,但请注意,每次订阅都会重新执行可观察对象(在 http 请求的情况下,这意味着您多次运行请求;不太理想……)。 -
最好不要将您的变量称为
recipeSubscription
,因为它包含Observable
,而不是Subscription
。订阅是subscribe()
返回的内容。换句话说:const subscription = observable.subscribe()
。 - 我看到您直接使用 Firebase SDK。您是否知道 AngularFire 库 ?
问题是,你返回了一个可观察对象,并在 Token() 的响应中重新分配它。
尝试为你现在拥有的可观察对象创建一个主题,我发现这些更容易使用。
public recipeSubscription: Subject<any> = new Subject();
将你的任务从
this.recipeSubscription = this.http.get....
更改为
let response = this.http.get....
在调用该函数的函数中订阅它:
response.subscribe((res) => {this.recipeSubscription.next(res)})
现在你可以直接在属性上订阅
this.dataStorage.recipeSubscription.subscribe((res) => {
// Do stuff.
});
this.dataStorage.getRecipes();
我希望这足以帮助你 :)