コールバック関数の実行時、Angular2コンポーネントの「this」は未定義です


92

RESTfulエンドポイントからデータをフェッチするサービスを呼び出すコンポーネントがあります。このサービスには、データをフェッチした後に実行するコールバック関数を指定する必要があります。

問題は、コールバック関数を使用して、コンポーネントの変数の既存のデータにデータを追加しようとすると、を取得することEXCEPTION: TypeError: Cannot read property 'messages' of undefinedです。なぜthis未定義なのですか?

TypeScriptバージョン:バージョン1.8.10

コントローラーコード:

import {Component} from '@angular/core'
import {ApiService} from '...'

@Component({
    ...
})
export class MainComponent {

    private messages: Array<any>;

    constructor(private apiService: ApiService){}

    getMessages(){
        this.apiService.getMessages(gotMessages);
    }

    gotMessages(messagesFromApi){
        messagesFromApi.forEach((m) => {
            this.messages.push(m) // EXCEPTION: TypeError: Cannot read property 'messages' of undefined
        })
    }
}

TypeScriptのどのバージョンを使用していますか?(これで確認できますtsc -v
リヌックス2016

forEachのため例外です。代わりにFor-ofを使用してください。
Pax Beach

回答:


155

Function.prototype.bind関数を使用します。

getMessages() {
    this.apiService.getMessages(this.gotMessages.bind(this));
}

ここで何が起こるかというとgotMessages、コールバックとしてを渡すことです。それが実行されているときは、スコープが異なるため、this期待どおりではありません。関数がにバインドされている新しい関数を返しますが、定義されています。
bindthis

もちろん、そこでも矢印関数を使用できます。

getMessages() {
    this.apiService.getMessages(messages => this.gotMessages(messages));
}

私はbind構文を好みますが、それはあなた次第です。

最初にメソッドをバインドするための3番目のオプション:

export class MainComponent {
    getMessages = () => {
        ...
    }
}

または

export class MainComponent {
    ...

    constructor(private apiService: ApiService) {
        this.getMessages = this.getMessages.bind(this);
    }

    getMessages(){
        this.apiService.getMessages(gotMessages);
    }
}

1
お疲れ様でした!そして、なぜこれが起こるのか説明してくれてありがとう。
Michael Gradek 16

ありがとうございました!OOPスタイルがJavaScriptの詳細(バインド)をリークしているという事実は悲劇的です。
skfd

21

またはあなたはこのようにそれを行うことができます

gotMessages(messagesFromApi){
    let that = this // somebody uses self 
    messagesFromApi.forEach((m) => {
        that.messages.push(m) // or self.messages.push(m) - if you used self
    })
}

13

関数参照を渡すだけなのでgetMessages、適切なthisコンテキストがありません。

thisその匿名関数内で使用するための適切なコンテキストを自動的にバインドするラムダを使用することで、簡単に修正できます。

getMessages(){
    this.apiService.getMessages((data) => this.gotMessages(data));
}

それでおしまい!ありがとう
Michael Gradek 16

完璧です。最もシンプルで効率的なソリューション。
Kon


0

関数を定義してください

gotMessages = (messagesFromApi) => {
  messagesFromApi.forEach((m) => {
    this.messages.push(m)
  })
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.