Axel
Axel

Reputation: 81

ngFor not re-rendering components when array changes

@Component({
  selector: 'app-comment-section',
  templateUrl: './comment-section.component.html',
  styleUrls: ['./comment-section.component.css']
})
export class CommentSectionComponent implements OnInit, OnDestroy {

  @Input()
  private commentable: Commentable;
  private commentRoom;
  private comments: Comment[] = [];
  private onNew: Subscription;
  private onDelete: Subscription;

  constructor(private service: CommentingService, private http: HttpClient) { }

  ngOnInit() {
    this.commentRoom = this.service.joinCommentsRoom(this.commentable.uuid);

    this.http.get<CommentsResponse>(this.commentable.url).subscribe(res => {
      this.comments = res.comments.rows;
    });

    this.onNew = this.commentRoom.newComment$.subscribe((comment) => {
      this.comments.push(comment);
    })

    this.onDelete = this.commentRoom.deletedComment$.subscribe((uuid) => {
      console.log('Comment deleted...')
      this.comments = this.comments.filter(comment => {
        return comment.uuid != uuid;
      });
    })

  }

  ngOnDestroy() {
    this.onNew.unsubscribe();
    this.onDelete.unsubscribe();
    this.commentRoom.reconnect.unsubscribe();
  }

}

I have a comment section, that is using a commenting service to get observables that emit new and deleted comments. Everything seems to work, except that the view doesn't re-render when this.comments is updated as a comment is created or deleted. I can see that the values are emitted with the console.log().

This is what the ngFor looks like in the view:

<app-comment class="comment" *ngFor="let entity of comments" [entity]="entity"></app-comment>

Is there something I'm doing wrong that is causing the view to not update when the array changes?

Kind regards, Axel

Upvotes: 1

Views: 4160

Answers (2)

ibenjelloun
ibenjelloun

Reputation: 7733

The NgForOf directive tracks by the default value, the value can still be the same even if the subvalues are changing: an [Object] is [Object] even after changing some nested values.

You can create a custom tracking function to specify what should be used to track the values :

<app-comment class="comment" *ngFor="let entity of comments; trackBy: trackByFn" 
 [entity]="entity">
</app-comment>

The function implementation must return what makes the entity unique :

trackByFn(index, entity) {
  return entity.id;
}

There is a running example in the angular.io documentation.

Upvotes: 1

timtoy1
timtoy1

Reputation: 31

Try separating the ngFor from the component you are attempting to iterate through.

<div *ngFor="let entity of comments">
  <app-comment class="comment"  [entity]="entity"></app-comment>
</div>

Sometimes, angular's onchanges hook does not register updates in cases where the child components are not directly visible

Upvotes: 1

Related Questions