"This" dari komponen Angular2 tidak ditentukan saat menjalankan fungsi callback


94

Saya memiliki komponen yang memanggil layanan untuk mengambil data dari titik akhir RESTful. Layanan ini perlu diberi fungsi panggilan balik untuk dijalankan setelah mengambil data tersebut.

Masalahnya adalah ketika saya mencoba menggunakan fungsi panggilan balik untuk menambahkan data ke data yang ada di variabel komponen, saya mendapatkan file EXCEPTION: TypeError: Cannot read property 'messages' of undefined. Mengapa tidak thisditentukan?

Versi TypeScript: Versi 1.8.10

Kode pengontrol:

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
        })
    }
}

Versi TypeScript mana yang Anda gunakan? (Anda dapat memeriksanya dengan tsc -v)
rinukkusu

Pengecualian karena forEach. Gunakan For-of sebagai gantinya.
Pax Beach

Jawaban:


159

Gunakan fungsi Function.prototype.bind :

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

Apa yang terjadi di sini adalah Anda meneruskan gotMessagessebagai callback, ketika itu sedang dijalankan cakupannya berbeda sehingga thistidak seperti yang Anda harapkan.
Itubind mengembalikan fungsi fungsi baru yang terikat pada thisAnda tetapkan.

Anda tentu saja dapat menggunakan fungsi panah di sana:

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

Saya lebih suka bind sintaks, tetapi terserah Anda.

Opsi ketiga untuk mengikat metode untuk memulai:

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

Atau

export class MainComponent {
    ...

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

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

1
Berhasil, terima kasih! Dan terima kasih telah menjelaskan mengapa ini terjadi.
Michael Gradek

Terima kasih! Fakta bahwa OOP-style membocorkan spesifikasi javascript (bind) itu tragis.
skfd

21

Atau Anda bisa melakukannya seperti ini

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

Karena Anda hanya meneruskan referensi fungsi, getMessagesAnda tidak memiliki thiskonteks yang tepat .

Anda dapat dengan mudah memperbaikinya dengan menggunakan lambda yang secara otomatis mengikat thiskonteks yang tepat untuk penggunaan di dalam fungsi anonim itu:

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

Itu dia! Terima kasih
Michael Gradek

Sempurna. Solusi paling sederhana dan efisien.
Kon

1

Saya memiliki masalah yang sama, diselesaikan dengan menggunakan () => {} sebagai gantinya function ()


ini tidak menambahkan informasi apapun ke jawaban yang ada
DerMike

0

Harap tentukan fungsi

gotMessages = (messagesFromApi) => {
  messagesFromApi.forEach((m) => {
    this.messages.push(m)
  })
}

ini tidak menambahkan informasi apapun ke jawaban yang ada
DerMike
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.