"Це" компонента Angular2 не визначено під час виконання функції зворотного виклику


94

У мене є компонент, який викликає службу для отримання даних із кінцевої точки 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)
rinukkusu

Виняток, оскільки forEach. Замість цього використовуйте For-of.
Pax Beach

Відповіді:


158

Використовуйте функцію Function.prototype.bind :

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

Тут відбувається те, що ви передаєте gotMessagesяк зворотний виклик, коли це виконується, область дії інша, і тому thisце не те, що ви очікували. Функція повертає нову функцію , яка прив'язана до ви визначили.
bindthis

Звичайно, ви також можете використовувати функцію стрілки :

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

Я віддаю перевагу bindсинтаксису, але це залежить від вас.

Третій варіант, щоб прив'язати метод до початку:

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

Дякую! Той факт, що в стилі ООП витікає специфіка JavaScript (bind), є трагічним.
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));
}

Це все! Дякую
Майкл Градек

Ідеально Найпростіше та ефективне рішення.
Kon

1

У мене така сама проблема, вирішена за допомогою () => {} замість функції ()


це не додає жодної інформації до існуючих відповідей
DerMike

0

Будь ласка, визначте функцію

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

це не додає жодної інформації до існуючих відповідей
DerMike
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.