ERROR TypeError: Cannot read properties of undefined (reading 'nativeElement') Angular

303 Views Asked by At

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!

0

There are 0 best solutions below