*ngFor DOM 回调后不刷新
*ngFor DOM not refreshing after callback
我在使用 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));
}
}
这是我试过的方法:
- 到处都是public
- 摆脱 ngOnInit
如何在这种情况下使用这一行 this.hubConnection.on('sendToAll', this.addMessage);
?
感谢您的帮助。
编辑 :
感谢 Supamiu,这是解决方案:
this.hubConnection.on('sendToAll', this.addMessage.bind(this));
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); });
Javascript 提供了一种将上下文注入方法调用的工具:bind.
您应该将 this.addMessage
更改为 this.addMessage.bind(this)
。
请记住,还有其他解决方案,就像 trichetriche 解释的那样,另一个是更改箭头函数的 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
上下文。
我在使用 ASP.NET Core、Angular 5 和 SignalR 开发应用程序时遇到了问题。
作为测试,我基于这个示例制作了一个简单的聊天应用程序:https://codingblast.com/asp-net-core-signalr-chat-angular/
但是,当我从
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));
}
}
这是我试过的方法:
- 到处都是public
- 摆脱 ngOnInit
如何在这种情况下使用这一行 this.hubConnection.on('sendToAll', this.addMessage);
?
感谢您的帮助。
编辑 :
感谢 Supamiu,这是解决方案:
this.hubConnection.on('sendToAll', this.addMessage.bind(this));
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); });
Javascript 提供了一种将上下文注入方法调用的工具:bind.
您应该将 this.addMessage
更改为 this.addMessage.bind(this)
。
请记住,还有其他解决方案,就像 trichetriche 解释的那样,另一个是更改箭头函数的 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
上下文。