开发者问题收集

Angular“无法读取未定义的属性‘subscribe’”

2017-10-24
178934

在开始问题之前,我想让您知道我已经进行了大型研究,我找不到解决方案(说明)为什么我会遇到此错误。

也请注意,我完全是Angular的新手,我才开始学习它的工作原理。

所以,我的问题是我在这个问题的标题中输入的问题。

我尝试做的是根据我在Udemy上购买的课程来构建登录系统。

我使用的代码如下:

auth.service.ts

786912877

data-storage.service.ts

921717467

header.component.ts

638324424

因此,不幸的是,我看不到此代码可能有什么问题。谁能发现我做错了什么?

注意: 我删除了代码的一部分只是为了使片段更可读。如果您需要其他任何部分,请随时问我,我将在此处提供。

更新#1

这就是<代码> header.component.html

575821032

3个回答

我使用未初始化的 EventEmitter 时遇到了同样的错误:

@Output() change: EventEmitter<any>;

而不是:

@Output() change: EventEmitter<any> = new EventEmitter<any>();

错误发生在尝试订阅更改事件的更高级别组件中。

Mark Wheeler
2018-08-02

问题似乎出在代码执行的顺序上,更具体地说是 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 库
AngularChef
2017-10-24

问题是,你返回了一个可观察对象,并在 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();

我希望这足以帮助你 :)

Benjamin Bloot
2017-10-24