I'm trying to make the chatMessages container to scroll to bottom when its loaded, when the scroll to bottom button is clicked and also when a new message is send. But i keep getting this error and nothing works. Below is the log I get :
ERROR TypeError: Cannot read properties of undefined (reading 'nativeElement')
at chatroom.component.ts:65:27
at timer (zone.js:2367:41)
at _ZoneDelegate.invokeTask (zone.js:402:31)
at core.mjs:25998:55
at AsyncStackTaggingZoneSpec.onInvokeTask (core.mjs:25998:36)
at _ZoneDelegate.invokeTask (zone.js:401:60)
at Object.onInvokeTask (core.mjs:26308:33)
at _ZoneDelegate.invokeTask (zone.js:401:60)
at Zone.runTask (zone.js:173:47)
at invokeTask (zone.js:483:34)
Ok this is what I did : Chatroom.component.ts
import { Component, Input, ViewChild, ElementRef, AfterViewInit, Output, HostListener, EventEmitter } from '@angular/core';
import { PickerComponent } from '@ctrl/ngx-emoji-mart';
import { User, Message } from 'src/user';
import { ChatService } from 'src/app/services/chat.service';
@Component({
selector: 'app-chatroom',
templateUrl: './chatroom.component.html',
styleUrls: ['./chatroom.component.css'],
})
export class ChatroomComponent implements AfterViewInit {
@ViewChild('chatMessages') chatMessages!: ElementRef<HTMLInputElement>;
@Input() selectedContact: User | null = null;
@Output() goBackClicked = new EventEmitter<void>();
message: string = '';
showEmojiPicker: boolean = false;
isMobile: boolean;
showScrollToBottomButton: boolean = false;
constructor(private chatService: ChatService) {
this.isMobile = window.innerWidth < 992;
}
ngAfterViewInit() {
this.scrollToBottom();
}
@HostListener('window:resize', ['$event'])
onResize(event: any) {
this.isMobile = event.target.innerWidth < 992;
}
goBack() {
this.goBackClicked.emit();
}
sendMessage() {
if (this.message.trim() === '') return;
const newMessage: Message = {
content: this.message,
sentByUser: true,
timestamp: new Date(),
};
if (this.selectedContact) {
this.selectedContact.messages.push(newMessage);
}
this.message = '';
this.scrollToBottom();
}
scrollToBottom() {
try {
setTimeout(() => {
this.chatMessages.nativeElement.scrollTop = this.chatMessages.nativeElement.scrollHeight;
}, 0);
}
catch (err) {
console.log(err)
}
}
}
Then in the html file :
<div class="container-fluid h-100 px-0 mx-0">
<div class="chat-container d-flex flex-column">
<div class="header d-flex align-items-center justify-content-between px-4 py-2" style="position: sticky; top: 0;" *ngIf="selectedContact">
<div class="contact_details row align-items-center">
<!-- Back button -->
<div class="col-auto" *ngIf="selectedContact && isMobile">
<button class="btn btn-primary" (click)="goBack()">
<i class="fa-solid fa-arrow-left"></i>
</button>
</div>
<div class="contact_image col-auto">
<img [src]="selectedContact.profileImage" alt="" class="rounded-circle" width="40">
</div>
<div class="contact_name col-auto">{{ selectedContact.name }}</div>
</div>
<div class="row align-items-center">
<div class="col video_call">
<a href=""><i class="fa-solid fa-video"></i></a>
</div>
<div class="col audio_call">
<a href=""><i class="fa-solid fa-phone"></i></a>
</div>
<div class="col menu">
<a href=""><i class="fa-solid fa-ellipsis-vertical fs-5"></i></a>
</div>
</div>
</div>
<div class="chat-messages pb-3" id="chatMessages">
<div *ngIf="!selectedContact || !selectedContact.messages.length" class="w-100 h-100 text-center d-flex justify-content-center align-items-center">
<h3>{{ selectedContact ? 'No messages yet!' : 'Select a contact to start a conversation!' }}</h3>
</div>
<div *ngFor="let message of selectedContact?.messages">
<div class="message-cont">
<div class="{{message.sentByUser ? 'sent' : 'received'}}">
<div class="message {{message.sentByUser ? 'sent' : 'received'}}">{{message.content}}</div>
<div class="msg_time">{{message.timestamp | date: 'h:mm a'}}</div>
</div>
</div>
</div>
<button *ngIf="selectedContact" class="scroll-to-bottom" (click)="scrollToBottom()">
<i class="fa-solid fa-chevron-down"></i>
</button>
</div>
<div class="chat-input" *ngIf="selectedContact">
<button class="btn px-2" (click)="toggleEmojiPicker()">
<i class="fa-regular fa-face-smile text-primary fs-5"></i>
</button>
<input
[(ngModel)]="message"
class="form-control"
placeholder="Type a message..."
#msg
/>
<button class="send btn btn-primary" (click)="sendMessage()">
<i class="fa-solid fa-paper-plane"></i>
</button>
</div>
<emoji-mart
*ngIf="showEmojiPicker"
(emojiSelect)="addEmoji($event)"
[isNative]="true"
[showPreview]="false"
[perLine]="8"
[emojiSize]="18"
></emoji-mart>
</div>
</div>
The chat messages has messages and it should scroll to the bottom that's to the last message when its loaded, the scroll to bottom is clicked or a new message sent but none of this happens. Please help!