Why does my ngFor consistently refresh while the array remains unchanged?

Issue at hand: Whenever I launch this component, the ngFor div continuously updates and causes my RAM to deplete. Typically, ngFor is triggered when the array is updated; however, in my case, the array (announcements) only updates once in the constructor. I am utilizing two ngFor divs:

<mat-tab label="Classroom"> 
        <div *ngFor="let announcement of announcements">
            <mat-card class="example-card">
                <mat-card-header>
                    <mat-card-subtitle>{{"Announcement: " + announcement.text}}</mat-card-subtitle>
                </mat-card-header>
                <mat-card-footer>
                    <div *ngFor="let comment of loadComments(announcement)">
                        <mat-card class="example-card comment">
                            <mat-card-header>
                              <mat-card-subtitle>{{"Comment: " + comment.text}}</mat-card-subtitle>
                            </mat-card-header>
                            <mat-card-content>
                        </mat-card>
                    </div>
                </mat-card-footer>
            </mat-card>
        </div>
    </mat-tab>

ts file:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { environment } from 'src/environments/environment';
import { Announcement } from '../model/announcement';
import { Classroom } from '../model/classroom';
import { User } from '../model/user';
import { Comment } from '../model/comment';
import { ClassroomService } from '../service/classroom.service';
import { CommentService } from '../service/comment.service';
import { AnnouncementService } from '../service/announcement.service';

@Component({
  selector: 'app-view-classroom',
  templateUrl: './view-classroom.component.html',
  styleUrls: ['./view-classroom.component.css']
})
export class ViewClassroomComponent implements OnInit {

  announcements: Announcement[] | undefined;
  comments: Comment[] | undefined;

  constructor(private classroomService: ClassroomService,
              private commentService: CommentService,
              private announcementService: AnnouncementService,
              private formBuilder: FormBuilder) 
  {
    this.classroomService.getClassroomUsers(JSON.parse(localStorage.getItem(environment.classroom) || ''), 'teachers').subscribe(
      (response: User[]) => this.teachers = response);
    this.classroomService.getClassroomUsers(JSON.parse(localStorage.getItem(environment.classroom) || ''), 'students').subscribe(
      (response: User[]) => this.students = response);
    this.classroomService.getClassroomOwner(JSON.parse(localStorage.getItem(environment.classroom) || '')).subscribe(
      (response: User) => this.owner = response);
    this.classroom = JSON.parse(localStorage.getItem(environment.classroom) || '');
    this.announcementService.getAnnouncementsByClassroom(JSON.parse(localStorage.getItem(environment.classroom) || '')).subscribe(
      (response: Announcement[]) => this.announcements = response);
  }

  ngOnInit(): void {
    
  }

  loadComments(announcement: Announcement){
    let an = announcement;
    this.commentService.getCommentsByAnnouncement(an).subscribe(
      (response: Comment[]) => this.comments = response);
    return this.comments;
  }

}

However, the problem disappears when I remove the internal ngFor loop. What steps should I take to resolve this?

Answer №1

What you are currently doing may not be the most efficient approach.

  loadComments(announcement: Announcement){
    let an = announcement;
    this.commentService.getCommentsByAnnouncement(an).subscribe(
      (response: Comment[]) => this.comments = response);
    return this.comments; // <-- previous values!!
  }

At this point, the method will indeed return an outdated version of this.comments, rather than the latest response data.

To fix this issue, consider modifying the method as follows:

  loadComments(announcement: Announcement):Observable<Comment[]>{
    let an = announcement;
    return this.commentService.getCommentsByAnnouncement(an);
  }

Furthermore, update the HTML code to incorporate the changes:

<ng-container *ngIg="loadComments(announcement) | async as comments"> 
    <div *ngFor="let comment of comments">
    ...
    </div>
</ng-container>

Answer №2

The issue you're encountering is due to the data being populated asynchronously. To address this, one solution is to implement a reactive programming approach using RxJs.

Step 1: Change static array definitions to Subjects (import from 'rxjs')

announcements: Announcement[] | undefined;
comments: Comment[] | undefined;

// Update the above two lines to:

announcements$: Subject<Announcement[] | undefined>;
comments$: Subject<Comment[] | undefined>;

Step 2: Update assignments

this.announcementService.getAnnouncementsByClassroom(
  JSON.parse(localStorage.getItem(environment.classroom) || '')
).subscribe(
  // (response: Announcement[]) => this.announcements = response <- update this to:
  (response: Announcement[]) => this.announcements$.next(response)
);

this.commentService.getCommentsByAnnouncement(an).subscribe(
  // (response: Comment[]) => this.comments = response <- update this to:
  (response: Comment[]) => this.comments$.next(response)
);
// return this.comments; <- this is not required any more

Step 3: Update HTML

<!-- old -->
<div *ngFor="let announcement of announcements">
<!-- new -->
<div *ngFor="announcements$ | async as announcement">

<!-- old -->
<div *ngFor="let comment of loadComments(announcement)">
<!-- new -->
<div *ngFor="comments$ | async as comment">

Answer №3

just make the following adjustments

*ngFor="let comment of loadComments(announcement)"

replace it with

*ngFor="let comment of comments"

also, update the function

loadComments(announcement: Announcement) {
    this.commentService.getCommentsByAnnouncement(announcement).subscribe((response: Comment[]) => {
        this.comments = response
    })
}

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

Unwillingness of Ajax to accept Names containing apostrophes as a parameter

$(".loadingPnl").removeClass('hdn'); var siteurlA = window.location.protocol + "//" + window.location.host + _spPageContextInfo.siteServerRelativeUrl; var callUrl = siteurlA + "/_layouts/15/SynchronyFinancial.Intranet/CreateMySite.aspx/S ...

What is the best way to retrieve the name of an element or component using JavaScript

I'm currently working on a webpage that includes ASP.NET panels and JavaScript which retrieves all components present on the page: var items = Sys.Application.getComponents(); My goal is to obtain the name/ID of each element stored in the 'item ...

Unable to establish connection with nodejs server from external devices

Currently, I am leveraging a React client along with a Node.js server (MERN Stack). The server operates smoothly on my computer; however, I encounter difficulties when attempting to connect from my mobile phone to the IPv4 of my PC using the correct port ...

"Sweet syntax" for assigning object property if the value is true

In the project I'm working on, I find myself dealing with a lot of parsing and validating tasks. This often results in 5-10+ lines of code like if(value) object.value = value. I considered using object.value = value || (your favorite falsy value) app ...

Vuex was unable to locate the required dependency

Currently, I'm following an instructional video that incorporates Vuex. As shown in my package.json dependencies, I have installed Vuex: { "name": "blabla", "version": "1.0.0", "description": "blablaa", "author": "blabla", "private": true, ...

ng-click-outside event triggers when clicking outside, including within child elements

I am looking to trigger a specific action when I click outside of the container. To achieve this, I have utilized the ng-click-outside directive which works well in most cases. However, there is one scenario where an issue arises. Inside the container, the ...

"Repetitive" elements arranged horizontally

My goal is to create a looped row of elements, similar to this design: https://i.sstatic.net/7cC2z.png This row should function like a carousel where clicking the "Next" button changes the current element and positions it in the center of the row. I envi ...

Creating a delay in a test to ensure a 5-second wait before validating the appearance of an element using React testing library

I am currently facing an issue in my React component where an element is supposed to appear after a delay of 5 seconds. I have been trying to write a test using 'jest fake timers' to check if the element appears after the specified time, but hav ...

How can we send data from several input fields using jQuery ajax?

I have several input fields, such as <p>Filter by age</p> <select class="filter-users"> <option value="under20">Under 20</option> <option value="20to40">20 to 40</option> </select> <p& ...

The first name of the user is not shown following the completion of the registration

I'm currently developing an application using React and Node.js. In the frontend, I have implemented a functionality where upon logging in, users are redirected from the /login route to the root route and greeted with their first name. However, when a ...

Develop an Innovative Data-Driven Application using AJAX Technology

After inputting an artist's name and clicking on the button, I expect to receive a visually appealing list of their songs. I am encountering the following issue: Whenever I hit the button, no results are being returned, and I am unsure of the reaso ...

Display the status in the textbox once a dropdown value has been selected

I have a function that allows me to add shops. Within this function, I am able to select whether the shop is OPEN or CLOSED. The goal is for the status of the shop, either OPEN or CLOSED, to appear in a textbox on another modal. When creating a user and ...

What steps should I take to establish routes in my node and express application that allow for authentication through a designated method?

Currently, I am following the backend set up tutorial from auth0, and I have a question regarding how to organize my routes in a separate file rather than in the app.js. In the tutorial, they demonstrate var authenticate = jwt({ secret: new Buffer(proc ...

Send information through a form by utilizing a personalized React hook

I'm having difficulty understanding how to implement a hook for submitting a form using fetch. Currently, this is what I have. The component containing the form: const MyForm = (): ReactElement => { const [status, data] = useSubmitForm('h ...

Setting the background color of a button within a template in an Angular 8 component using style.background

I have been exploring the different versions of Angular and their changes. Currently, I am enrolled in an Angular course on Udemy where I have installed Angular 8. In the course, it is mentioned to use style.backgroundColor on a button inside the template ...

Adjust the size of the input field as text is being typed in

Can a text input box be automatically resized as text is entered? I've been looking online but haven't come across any solutions. ...

Is it possible to transform a .csv document into a JavaScript array with dictionaries? Each dictionary's keys would correspond to the column headers in the .csv file, and the values would be the

Let's imagine a scenario where I have a .csv file with the column headers listed in the first row, and their respective values are provided in the subsequent rows as shown below: index,id,description,component,service 0,5,lorem ipsum,7326985,Field Ser ...

Encountering an issue with importing from 'sockjs-client' in TypeScript

I am a beginner with Angular and TypeScript. To get started, I used npm to install the following package: npm install --save sockjs-client I attempted to import it in my chat.component.ts file like this: import * as SockJS from 'sockjs-client'; ...

Guide on displaying applicant name in the show route of your node.js/mongoDB application

Currently working on a website where applications are being accepted. In the admin panel, I want to display a list of all applicants and allow users to click on a name to view more information. However, I'm facing an issue where the same applicant is ...

The Google API is experiencing issues when using input that has been added on

Situation: In my attempt to integrate a Google address search feature into an online shopping website, I encountered a challenge. I don't have direct access to the website's HTML code, but I can insert code snippets in the header, footer, and in ...