Struggling to solve a never-ending loop problem in a messaging application

I am currently in the process of developing a chat application. During the initialization of the chat page, I am checking for messages and storing them in an array.

  ngOnInit() {
    this.messageService.getMessages().doc(`${this.sortItineraries[0] + '-' + this.sortItineraries[1]}`)
    .onSnapshot((doc) => {
      console.log('Initializing message.page in snapshot', doc.data().message);
      this.messages = [];
      this.messages = doc.data();
      console.log('Initializing message.page variable', this.messages);
    });
  }

The issue of an infinite loop arises when sending a message using the following code

  getMessages() {
    return this.allMessages;
  }

  getAllMessages() {
    return this.allMessages;
  }

  async createMessage(itineraries) {
    console.log('Creating Message');
      const docRef = await firebase.firestore().doc(`messages/${itineraries}`).set({
      message: []
    });
  }

  async sendMessage(id, content, userId) {

    this.allMessages.doc(`${id}`)
    .onSnapshot((doc) => {
      if (doc.exists) {
        console.log('sendMessage doc exists');
        this.send(id, content, userId);
      } else {
        this.createMessage(id)
        .then(() => {
          console.log('sendMessage !doc exists');
          this.send(id, content, userId);
        });
      }
    });
  }

  async send(id, content, userId) {
    console.log('send');
    const uid = this.loggedInUser.uid;
    const ref = this.afs.collection('messages').doc(id);
    return ref.update({
      message: firebase.firestore.FieldValue.arrayUnion({
        content,
        createdAt: Date.now(),
        userId
      })
    });
  }
<ion-content>
  <ion-list lines="none">
    <ion-item *ngFor="let message of messages.message">
      <div size="9" *ngIf="myItinerary.userId !== message.userId" class="message other-user">
        <span>{{message.content}}</span>
        <div class="time" text-right><br>
        {{message.createdAt | date: 'short'}}</div>
        </div>

      <div offset="3" size="9" *ngIf="myItinerary.userId === message.userId" class="message me" slot="end">
        <span>{{message.content}}</span>
        <div class="time" text-right><br>
        {{message.createdAt | date: 'short'}}</div>
        </div>
    </ion-item>
  </ion-list>
</ion-content>

<ion-footer>
  <ion-toolbar light="light">
    <ion-row align-items-center no-padding>
      <ion-col size="8">
        <textarea autosize maxRows="3" [(ngModel)]="newMsg" class="message-input"></textarea>
      </ion-col>
      <ion-col size="3">
        <ion-button expand="block" fill="clear" color="primary" [disabled]="newMsg === ''" class="msg-btn"
        (click)="sendMessage()">
        <ion-icon name="ios-send" slot="icon-only"></ion-icon>
      </ion-button>
      </ion-col>
    </ion-row>
  </ion-toolbar>
</ion-footer>

https://i.stack.imgur.com/2zIw0.png

The screenshot highlights the console logs that keep looping between the service responsible for creating and sending messages to the Firebase backend and the initialization process. This loop continues until exiting the app and deleting the messages in Firebase.

In the service, I first check if the document is created before proceeding with pushing the messages into the array stored in Firebase

 async sendMessage(id, content, userId) {

    this.allMessages.doc(`${id}`)
    .onSnapshot((doc) => {
      if (doc.exists) {
        console.log('sendMessage doc exists');
        this.send(id, content, userId);
      } else {
        this.createMessage(id)
        .then(() => {
          console.log('sendMessage !doc exists');
          this.send(id, content, userId);
        });
      }
    });
  }

If the document does not exist, I create it before adding the messages to the array in Firebase

  <ion-list lines="none">
    <ion-item *ngFor="let message of messages.message">

Answer №1

It seems that the issue stems from a couple of key behaviors:

  1. When a new value is assigned to messages.message, even if it appears to be the same as JSON, all objects have new pointers.
  2. As a result, ngFor believes it has received a new array with different objects.
  3. This causes ngFor to discard old ion-items and initialize them again for the 'new' objects, essentially triggering ngOnInit in each of them.

The solution to this problem involves adding trackBy to ngFor (learn more here).

Another possible scenario is that some of the methods being used return an infinite Observable. The fix for this involves adding operators like take(1) or filter(someFilterFunc) to your pipe (for detailed information, refer to this link).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Include the designated return type within a fat arrow function

No matter how hard I look, I cannot figure out the correct way to combine return type annotation with fat arrow syntax. class BasicCalculator{ value:number; constructor(value:number=0){ this.value=value; } add= (operand:number)=> ...

"Encountering a 404 (Not Found) error when attempting to access local backend APIs through Angular

Recently, I integrated Angular Universal into my project to enhance performance and improve SEO. Everything was working smoothly when I ran 'ng serve', with the app able to communicate with the backend. However, when I tried running 'npm run ...

I am in need of assistance with incorporating a particular hibernate Inheritance mapping into my project

I am dealing with a situation where I have two classes, parent and child, with a self-referential relationship on the child side. The database is set up with separate tables for both parent and child, sharing the same "id", and using the column "holder" as ...

Troubleshooting routing: The Location.path() function consistently returns an empty string

I stumbled upon this tutorial which seems to be the most up-to-date example for testing routing. I'm eager to incorporate mock components in my testing strategy eventually. Unfortunately, when trying out the provided plunker, I encountered some issues ...

Employing Bazel in conjunction with Lerna and Yarn workspaces

It seems that a lot of people are currently utilizing lerna and/or yarn workspace. I'm thinking about either transitioning from them to Bazel, or perhaps integrating them with Bazel in conjunction with an example project for guidance. Take for insta ...

Extract the values from HTTP GET request by Id (Observable) and assign them to variables within the component

Hello everyone, it's been a while since I posted on here. Thank you all for your help so far, but I'm facing some difficulties with my Angular+2 web app. I have a User component and a user.service.ts that handles HTTP requests to get user data in ...

What is the reason for VS Code recognizing an import as valid while WebPack does not approve it?

I believe the root of the problem lies in the version of WebPack I am using ("webpack-cli": "3.3.11"). Before embarking on another round of debugging to upgrade WebPack (attempted version 5 but faced issues due to lack of a config file) ...

When importing a React Component with styling into the pages folder, it fails to function properly

I created a component in my components directory with custom styling: // import Link from "next/link"; import {Link} from "react-scroll" export default function Navbar() { return ( <div className="fixed w-full h-[79px] fle ...

Is Intellisense within HTML not available in SvelteKit when using TypeScript?

Having trouble with intellisense inside HTML for a simple page component. Also, renaming properties breaks the code instead of updating references. Typescript version: 4.8.4 Below is the code snippet: <script lang="ts"> import type { Bl ...

Can you explain the significance of triple brackets (e.g. {{{ content }}}) in the context of Javascript/Typescript?

As I delve into the code of a fresh project in which I hope to contribute, I have come across numerous methods defined with triple brackets, like so: deinitialize() {{{ this.destroyed = true; $(window).off("resize", this.resize as () => void); ...

Angular 12 app does not have Express server searching for static files

Context I am in the process of transferring an Angular application to a GKE cluster. Unfortunately, due to company policy, the base docker image I am required to use does not support the installation of new software such as shell or Angular CLI commands l ...

The CORS policy has blocked access to XMLHttpRequest at 'https://saja.smjd.ir/api/Account/login' from the specified origin 'http://**'

I have successfully completed my project using Angular 9 on the frontend and asp.net core 3 on the backend, and deployed it to a server. However, I am facing an issue when trying to obtain or use a token from the server. Access to XMLHttpRequest at 'h ...

Encountered an issue with the Dynamic Form: TypeError - The property 'value' is undefined and cannot be read

RESOLVED An incorrect value was causing an issue with the onChange function. public onChange = (e:any, key:any) => { this.setState({ [key]: e.target.value }); }; I'm struggling to resolve an error while inputting data into my form in T ...

Angular does not support node version 18 or lower

When trying to update my node package, I encountered a warning message. Alert: Angular does not support the current version of Node (18.10.0). If anyone has a solution for this issue, I would greatly appreciate the help. I updated my node using the down ...

Conditional type in Typescript can be used to infer tuple types

Why are output1 and output2 not both inferred as [number, number, number] in the following code snippets? Snippet 1 : type InferTuple1<T> = T extends any[] ? [...T]: never; const func1 = <T>(t: InferTuple1<T>) => t; const output1 = ...

Harnessing the power of Heatmaps in Angular 6

Currently, I am developing a data visualization project using angular6. I would greatly appreciate any assistance on how to incorporate heatmaps into the angular6 application. Thank you in advance for your help! ...

Potential solution for communication issue between Angular CLI and Flask due to cross-origin error

Initially, the user id and password are submitted from the UI (angular) to Flask: public send_login(user){ console.log(user) return this.http.post(this.apiURL+'/login',JSON.stringify(user),this.httpOptions) .pip ...

Applause tally problem in Ionic3

For my university project, I am utilizing Ionic-3 and attempting to achieve a similar effect as shown in this example. Please take a look at my code on StackBlitz. I am encountering an issue where I want the count circle to move from the bottom to the top ...

Adaptable Bootstrap Button that Adjusts to Different Screen Sizes

I want this button to adjust its size according to the screen dimensions. The current code keeps the button fixed in place. See below for the code snippet. <button type="button" [className]="'btn btn-block m-0'" kendoButton ...

An issue has occurred: changes.forEach does not function as expected

Encountered an issue while attempting to retrieve data from Firestore using Angular/Ionic. PizzaProvider.ts getAllPizzas() { return this._afs.collection<Pizzas>('pizzas', ref => ref); } pizzas-list.ts pizzas: Observable<any[]& ...