I have simple ngFor in which I am showing list
<a *ngFor="let user of chatsLists" (click)="viewChat(user)">
<div [ngClass]="{'align-items-center': !user.isActiveChat}">
<span >
<img [src]="user.userid.userImage" alt="Avatar">
<!-- <span ></span>
<i></i> -->
</span>
<div >
<h6 >{{user.userid.userName}}
</h6>
</div>
</div>
</a>
and function from api I am getting data
chatsLists: any; //also tried with chatsLists = [];
getChats() {
this.api.getAllChats().subscribe((res: any) => {
if (res.success) {
this.chatsLists = res.data;
this.chatdetails = this.chatsLists[0].messages;
this.showChats = true;
}
else {
}
})
}
Its not updating the ngFor loop and if I click on any input on screen and remove hover from it then its showing the loop state is not updating that's mean
Also I try to just place in html
<p *ngIf="showChats">Show </p>
and in my function I change the bool value but in console I can see its showing true but its not reflecting in html file
full code of component.ts
this.showChats = true;
import { Component, ViewChild, ElementRef, OnInit, ChangeDetectionStrategy, Renderer2, Inject, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { ChatService } from './chat.service';
import { Chat, UsersChat } from './chat.model';
import { DOCUMENT } from '@angular/common';
import { ConfigService } from 'app/shared/services/config.service';
import { Subscription } from 'rxjs';
import { ApiService } from 'app/services/api/api.service';
@Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./chat.component.scss'],
providers: [ChatService]
})
export class ChatComponent implements OnInit, OnDestroy {
chats: Chat[] = [];
activeChat: UsersChat;
usersChat: UsersChat[] = [];
activeChatUser: string;
activeChatUserImg: string;
loggedInUserImg: string;
newMessage = "";
searchQuery: string = '';
placement = "bottom-right";
isContentOverlay = false;
activeIndex = 0;
chatdetails = [];
showChats: any;
public config: any = {};
layoutSub: Subscription;
chatsLists: any;
messages = new Array();
item: number = 0;
constructor(private api: ApiService, private elRef: ElementRef, private renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
private configService: ConfigService, private cdr: ChangeDetectorRef,
private chatService: ChatService) {
this.config = this.configService.templateConf;
this.usersChat = chatService.usersChat;
this.activeChat = chatService.usersChat.find(_ => _.isActiveChat);
this.chats = this.activeChat.chats;
this.activeChatUser = this.activeChat.name;
this.activeChatUserImg = this.activeChat.avatar;
this.loggedInUserImg = "assets/img/portrait/small/avatar-s-1.png"
this.renderer.addClass(this.document.body, "chat-application");
}
ngOnInit() {
this.getChats();
}
ngOnDestroy() {
if (this.layoutSub) {
this.layoutSub.unsubscribe();
}
this.renderer.removeClass(this.document.body, "chat-application");
}
getChats() {
this.api.getAllChats().subscribe((res: any) => {
if (res.success) {
this.chatsLists = res.data;
this.chatdetails = this.chatsLists[0].messages;
this.showChats = true;
}
else {
}
})
}
//send button function calls
onAddMessage() {
if (this.newMessage != "") {
this.activeChat.chats.push({
isReceived: false,
time: "",
messages: [this.newMessage],
messageType: 'text'
})
this.newMessage = "";
}
}
viewChat(chat: UsersChat) {
this.usersChat.forEach(chat => {
if (chat.userId === this.activeChat.userId) {
chat.isActiveChat = false;
}
})
this.activeChat = chat;
this.activeChat.isActiveChat = true;
this.chats = this.activeChat.chats;
this.activeChatUser = this.activeChat.name;
this.activeChatUserImg = this.activeChat.avatar;
this.isContentOverlay = false;
}
onSidebarToggle() {
this.isContentOverlay = true;
}
onContentOverlay() {
this.isContentOverlay = false;
}
}
CodePudding user response:
It may be caused because of the OnPush strategy. Perhaps because of the async nature of the http request and callback, the change detection has already happened.
I would suggest starting by changing your subscription strategy to using the async pipe.
For example:
setChats() {
this.chats$ = this.api.getAllChats().pipe(
filter((res: any) => res.success),
tap((res) => {
this.chatsLists = res.data;
this.chatdetails = this.chatsLists[0].messages;
this.showChats = true;
})
);
Something like this. Then using {{ chats$ | aysnc }} on the HTML template.
The code above I suggested could do a lot of improving by typing variables and composing better streams, but you should definitely stick to the async pipe when using OnPush.
CodePudding user response:
ChangeDetectionStrategy.OnPush
means that if you make async calls outside the component you have to tell the component to update. Are you sure you want it? If you do still want to have it add changeDetectorRef to your constructor and then have it mark the component as ready for change detection:
constructor(..., private changeDetectorRef: ChangeDetectorRef) {
And then in your getChats function you have
getChats() {
this.api.getAllChats().subscribe((res: any) => {
if (res.success) {
this.chatsLists = res.data;
this.chatdetails = this.chatsLists[0].messages;
this.showChats = true;
this.changeDetectorRef.markForCheck(); //Add it here
}
})
}