“This” của thành phần Angular2 không được xác định khi thực thi hàm gọi lại


94

Tôi có một thành phần gọi một dịch vụ để tìm nạp dữ liệu từ một điểm cuối RESTful. Dịch vụ này cần được cung cấp một hàm gọi lại để thực thi sau khi tìm nạp dữ liệu nói trên.

Vấn đề là khi tôi thử sử dụng hàm gọi lại để nối dữ liệu vào dữ liệu hiện có trong biến của thành phần, tôi nhận được a EXCEPTION: TypeError: Cannot read property 'messages' of undefined. Tại sao thiskhông xác định?

Phiên bản TypeScript: Phiên bản 1.8.10

Mã bộ điều khiển:

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

Bạn đang sử dụng phiên bản TypeScript nào? (Bạn có thể kiểm tra xem có tsc -v)
rinukkusu

Ngoại lệ vì forEach. Sử dụng For-of thay thế.
Bãi biển Pax

Câu trả lời:


158

Sử dụng hàm Function.prototype.bind :

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

Điều xảy ra ở đây là bạn chuyển nó gotMessagesdưới dạng một cuộc gọi lại, khi điều đó đang được thực thi thì phạm vi sẽ khác và vì vậy thiskhông phải là những gì bạn mong đợi.
Các bindhàm trả về một chức năng mới được ràng buộc với thisbạn xác định.

Tất nhiên, bạn cũng có thể sử dụng hàm mũi tên ở đó:

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

Tôi thích bindcú pháp hơn, nhưng nó tùy thuộc vào bạn.

Tùy chọn thứ ba để liên kết phương thức bắt đầu bằng:

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

Hoặc là

export class MainComponent {
    ...

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

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

1
Đã làm việc, cảm ơn! Và cảm ơn vì đã giải thích tại sao điều này xảy ra.
Michael Gradek,

Cảm ơn bạn! Thực tế là kiểu OOP đang làm rò rỉ các chi tiết cụ thể của javascript (bind) là một bi kịch.
skfd

21

Hoặc bạn có thể làm như thế này

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

Bởi vì bạn chỉ truyền tham chiếu hàm getMessagesmà bạn không có thisngữ cảnh phù hợp .

Bạn có thể dễ dàng khắc phục điều đó bằng cách sử dụng lambda tự động liên kết thisngữ cảnh phù hợp để sử dụng bên trong hàm ẩn danh đó:

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

Điều đó là vậy đó! Cảm ơn
Michael Gradek

Hoàn hảo. Giải pháp đơn giản và hiệu quả.
Kon

1

Tôi gặp vấn đề tương tự, được giải quyết bằng cách sử dụng hàm () => {} thay vì hàm ()


điều này không thêm bất kỳ thông tin nào vào các câu trả lời hiện có
DerMike

0

Vui lòng xác định chức năng

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

điều này không thêm bất kỳ thông tin nào vào các câu trả lời hiện có
DerMike
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.