* ngFor DOM在回调后没有刷新

时间:2018-03-19 10:25:38

标签: angular typescript asp.net-core asp.net-core-signalr

使用ASP.NET Core,Angular 5和SignalR开发应用程序时,我遇到了一个问题。

作为测试,我根据此示例创建了一个简单的聊天应用:https://codingblast.com/asp-net-core-signalr-chat-angular/
但是,当我从

修改chat.component.ts文件时
this.hubConnection.on('sendToAll', (nickname: string, message: string) => { this.messages.push(new Message(nickname, message)); });
// or this line
this.hubConnection.on('sendToAll', (nickname: string, message: string) => { this.addMessage(nickname, message); });

this.hubConnection.on('sendToAll', this.addMessage);

DOM未更新。

我已经逐步完成了,我设法弄清楚当回调到来时,它实际上是组件的另一个实例......所以每个字段都是未定义的。

以下是完整的组件:

chat.component.html

<section class="card">
    <div class="card-body" *ngIf="messages !== undefined">
        <div *ngFor="let msg of messages">
            <strong>{{msg.nickname}}</strong>: {{msg.message}}
        </div>
    </div>
    <div class="card-footer">
        <form class="form-inline" (ngSubmit)="sendMessage()" #chatForm="ngForm">
            <div class="form-group">
                <label class="sr-only" for="nickname">Nickname</label>
                <input type="text" id="nickname" name="nickname" placeholder="Nickname" [(ngModel)]="nickname" required />
            </div>
            <div class="form-group">
                <label class="sr-only" for="message">Message</label>
                <input type="text" id="message" name="message" placeholder="Your message" [(ngModel)]="message" required />
            </div>
            <button class="btn btn-sm" type="submit" id="sendmessage" [disabled]="!chatForm.valid">Send</button>
        </form>
    </div>
</section>

chat.component.ts

import { Component, OnInit } from '@angular/core';
import { HubConnection } from '@aspnet/signalr';
import { Message } from '../../models/message';

@Component({
    selector: 'app-chat',
    templateUrl: './chat.component.html',
    styleUrls: ['./chat.component.css']
})
export class ChatComponent implements OnInit {
    private hubConnection: HubConnection;

    public nickname: string;
    public message: string;

    public messages: Message[];

    constructor() {
        this.messages = [];
    }

    ngOnInit() {
        this.hubConnection = new HubConnection('http://localhost:55233/chat');

        this.hubConnection.start().then(() => console.log('connection started')).catch(err => console.error(err));

        this.hubConnection.on('sendToAll', this.addMessage);
    }

    private addMessage(nickname: string, message: string): void {
        // this line is useful to avoid undefined error
        // due to the callback pointing to another instance of this component...
        if (this.messages === undefined) {
            this.messages = [];
        }

        this.messages.push(new Message(nickname, message));
    }

    public sendMessage(): void {
        this.hubConnection
            .invoke('sendToAll', this.nickname, this.message)
            .catch(err => console.error(err));
    }
}

这是我尝试过的:

  • 到处公开
  • 摆脱ngOnInit

如何在此上下文中使用此行this.hubConnection.on('sendToAll', this.addMessage);? 谢谢你的帮助。

编辑
感谢Supamiu,这是解决方案:

this.hubConnection.on('sendToAll', this.addMessage.bind(this));

2 个答案:

答案 0 :(得分:2)

this.hubConnection.on('sendToAll', this.addMessage);

相当于

this.hubConnection.on('sendToAll', function(x) { this.addMessage(x); });

在javascript中,你必须在编写函数时使用闭包,或者使用胖箭头。这会给出

const that = this;
this.hubConnection.on('sendToAll', function(x) { that.addMessage(x); });
// or
this.hubConnection.on('sendToAll', x => { this.addMessage(x); });

答案 1 :(得分:1)

Javascript提供了一种将上下文注入方法调用的工具:bind

您应该将this.addMessage更改为this.addMessage.bind(this)

请记住,还有其他解决方案,例如解释过的三个解决方案,另一个解决方案是更改addMessage箭头函数,因为箭头函数保持this上下文:

private addMessage = (nickname: string, message: string) => {
    // this line is useful to avoid undefined error
    // due to the callback pointing to another instance of this component...
    if (this.messages === undefined) {
        this.messages = [];
    }

    this.messages.push(new Message(nickname, message));
}

通过这样做,您仍然可以使用this.addMessage而无需绑定this上下文。