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

Expanding the visual in a spacious display with the help of ng-carousel from the Bootstrap framework

I have created a slider with multiple images on a website using Angular 4. The slider is displayed in a small area of the webpage and I would like to add a feature where the user can click on an image to view it in a larger screen or window. This could i ...

Utilize Typescript to inject types into a library

I have a code snippet that reads data from a JSON file and creates a type based on it, which is then used for further operations. import jsonData from './mydata.json' type CustomType = typeof jsonData .... This process ensures that the generate ...

The main source for loading the 'XYZComponent' cannot be located

There's an issue I'm facing where ng2 code is being loaded into a .Net MVC component, but the console is showing the following error: EXCEPTION: Uncaught (in promise): Error: Cannot find primary outlet to load 'UsersComponent' Error: C ...

retrieving dynamic information from beyond the subscribe function

In order to implement canActivate for user routes, I need to first verify the validity of the access token. Below is the approach I am taking: export class AuthGuard implements CanActivate { data:Array<Object>; constructor(private base: BaseServ ...

Exploring JSON data in Angular

I am currently working with a Json file that contains two different objects: readers and books. Here is an example of the structure: { "users": [{ "id": 1, "username": "peterB", }, { "id": 2, "username": "MaryC" ...

Encountering Issues with Accessing Property

Upon trying to run my code, the console is displaying an error that I am unable to resolve. The error specifically states: "TypeError: Cannot read property 'author' of undefined." View the StackBlitz project here The error seems to be coming fr ...

Retrieve all the items listed in the markdown file under specific headings

Below is an example of a markdown file: # Test ## First List * Hello World * Lorem Ipsum * Foo ## Second List - Item 1 ## Third List + Item A Part of Item A + Item B ## Not a List Blah blah blah ## Empty ## Another List Blah blah blah * ITEM # ...

I rely on the angular-responsive-carousel library for my project, but unfortunately, I am unable to customize the arrow and dots

When it comes to CSS, I utilize ng deep style in Angular 10 to make changes for browser CSS. However, I am facing an issue where the problem is not being resolved by my CSS code. Here is a snippet of my code: > ::ngdeep .carousel-arrow { > b ...

Navigating within the same URL page in Ionic 5

Hey there, I'm trying to set up a routing system where a page can navigate to the same URL but with different parameters. However, it seems like my routing is working fine for other pages but not for navigating to the exact same URL page. Here's ...

Angular2 allows you to create pipes that can filter multiple values from JSON data

My program deals with an array of nested json objects that are structured as follows: [{name: {en:'apple',it:'mela'}},{name:{en:'coffee',it:'caffè'}}] I am looking to implement a pipe that can filter out objects b ...

various positions for ngb properties

My input field has both a tooltip and a dropdown attached to it using the ngb attributes: <input placement="right" ngbTooltip="Search" [ngbTypeahead]="search" /> The issue I'm facing is that I want the tooltip to appear on the right ...

"Implementing Two-Way SSL with Angular 2 and BrowserSync

Currently, I am working on an Angular2 application that requires two-way SSL authentication. This means that the browser needs to present a valid (PFX) certificate in order to access the application. For deployment, I am using lite-server (which utilizes B ...

Angular 2's HTTP Interceptor: Enhancing your HTTP Requests

For my Angular 2 app, I'm looking to include an HTTP interceptor that will verify the HTTP status code for each response. In case the status code is 401, I would like to automatically redirect the user to the login page. Does anyone know of a straigh ...

Having trouble installing memlab using the npm package

Recently, I made an attempt to install the memlab library from Meta's GitHub. Initially, when I installed it without using the -g flag, the installation was successful. However, I encountered an issue where I could not execute any of the memlab comman ...

Guide on inserting tooltip to designated header column in primeNG data table

Html <p-table #dt1 [columns]="cols" [value]="cars1"> <ng-template pTemplate="header" let-columns> <tr> <th *ngFor="let col of columns"> {{col.header}} </th> ...

Using p5.js with TypeScript and Webpack is not supported

I'm currently working on a library project that involves utilizing p5.js. Specifications Here is a snippet of my Webpack configuration: const path = require('path'); module.exports = { entry: './start.ts', output: { ...

Issues arise when using Android BluetoothLeAdvertiser in Nativescript applications

I've been working on creating a Nativescript application that can send Bluetooth low energy advertisements. Since there are no existing Nativescript plugins for this functionality, I decided to develop a Java library (with plans to add a Swift library ...

Modify the style of an element using a media query and Angular 4

Is there a way to update a class of an element based on the browser's width in my .ts file? matchMedia('(max-width: 400px)').addListener((mql => { if (mql.matches) { this.myclass = 'toggled'; } })); In the HTML, it shou ...

The TypeScript in the React-Native app is lacking certain properties compared to the expected type

I recently integrated the https://github.com/react-native-community/react-native-modal library into my project and now I need to create a wrapper Modal class. Initially, I set up an Interface that extends multiple interfaces from both react-native and reac ...

Angular generates a dynamic interface to fetch data from Wordpress REST API posts (special characters in property names are causing issues)

I've been developing a front-end Angular application that interacts with the Wordpress REST API to fetch and display post data. My goal is to create an interface to handle the responses and render the posts in the template. However, I encountered an ...