Search code examples
javascriptangulartypescriptfrontendngfor

Why is my ngFor always updating, but array is not


Problem is: When I start this component, my ngFor div always updates and my RAM becomes empty. As I know, ngFor updates when array is updated, but my array(announcements) update only once, in constructor. I have 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;
  }

}

But when i remove inner ngFor, problem is gone. What should i do?


Solution

  • What you are doing is wrong.

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

    As it is right now this metod will return an old version of this.comments, not the one from the response.

    Change the metode like this:

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

    And in the html file:

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