I'm new to Angular, working with Angular 12 for a school assignment, trying to build a chat window of sorts that updates itself whenever the user sends a message, but I can't find a way to make it re-render when I add a new object to the array.
chat.component.ts:
@Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss']
})
@Injectable({ providedIn: 'root' })
export class ChatComponent implements OnInit {
messageArray: Array<any>;
constructor(private changeDetector: ChangeDetectorRef) {
this.messageArray = [{message: "test message 1", style: "answer"}];
}
ngOnInit(): void {}
addMessage(message: string, style: string): void {
this.messageArray = [...this.messageArray, {message: message, style: style}];
this.changeDetector.detectChanges();
console.log(this.messageArray);
}
}
chat.component.html:
<div class="container chatContainer">
<div class="row" *ngFor="let message of messageArray">
<div class="col">
<div class="text-wrap text-break message {{message.style}}">
{{message.message}}
</div>
</div>
</div>
</div>
I tried updating the array both with [...array] and with .push(), tried using [...array] to create a new array after pushing, tried both ChangeDetectionStrategy.Default and .OnPush, and tried doing all of those things also in the parent component that calls my addMessage() method. In all attempts, the array would log to the console correctly, but refuse to update the view.
Any ideas?
If i were you, i would rather use a BehaviorSubject and do something like this:
@Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss']
})
@Injectable({ providedIn: 'root' })
export class ChatComponent implements OnInit {
messageArray: BehaviorSubect<Array<any>>;
constructor(private changeDetector: ChangeDetectorRef) {
this.messageArray = new BehaviorSubject<Array<any>>([{message: "test message 1", style: "answer"}]);
}
ngOnInit(): void {}
addMessage(message: string, style: string): void {
this.messageArray.next([...this.messageArray, {message: message, style: style}]);
}
}
chat.component.html:
<div class="container chatContainer">
<div class="row" *ngFor="let message of messageArray | async">
<div class="col">
<div class="text-wrap text-break message {{message.style}}">
{{message.message}}
</div>
</div>
</div>
</div>
A colleague suggested I use @ViewChild to call the Chat component instead. So I removed the @Injectable from the Chat as zer0 suggested, and changed its parent Home component to this:
export class HomeComponent implements OnInit {
@ViewChild(ChatComponent) private chatComponent: any;
constructor(private cdr: ChangeDetectorRef) {
}
ngOnInit(): void {
}
onSend(): void {
this.chatComponent.addMessage("test message", "question");
this.cdr.detectChanges();
}
}
Works now. Thanks!
Edit: a word