ChatStateService is the centralized Angular service for managing active chat state across the CometChat Angular UIKit. It provides a single source of truth for the currently active chat entity (User, Group, or Conversation) in your application.The service is provided at the root level (providedIn: 'root') and is available throughout your application via Angular dependency injection.
For RxJS-based reactivity and integration with existing observable-based code, ChatStateService provides Observable streams derived from the underlying signals via toObservable().
Observable
Type
Description
activeUser$
Observable<CometChat.User | null>
Observable stream that emits whenever the active user changes.
activeGroup$
Observable<CometChat.Group | null>
Observable stream that emits whenever the active group changes.
activeConversation$
Observable<CometChat.Conversation | null>
Observable stream that emits whenever the active conversation changes.
Setter methods update the active chat state. They enforce mutual exclusivity — only one chat entity (User or Group) can be active at a time.
Method
Parameters
Return Type
Description
setActiveUser(user)
user: CometChat.User | null
void
Sets the active user. If user is non-null, automatically clears the active group (mutual exclusivity).
setActiveGroup(group)
group: CometChat.Group | null
void
Sets the active group. If group is non-null, automatically clears the active user (mutual exclusivity).
setActiveConversation(conversation)
conversation: CometChat.Conversation | null
void
Sets the active conversation and extracts the conversationWith entity. If the entity is a CometChat.User, calls setActiveUser(); if a CometChat.Group, calls setActiveGroup(). Passing null clears user and group.
clearActiveChat()
—
void
Clears all active state: user, group, and conversation are set to null. Also clears the internal active conversation in ConversationsService.
Getter methods return the current value of a signal as a one-time read without subscribing to changes. Use these in event handlers or one-time operations.
Method
Return Type
Description
getActiveUser()
CometChat.User | null
Returns the current active user, or null if no user is active.
getActiveGroup()
CometChat.Group | null
Returns the current active group, or null if no group is active.
getActiveConversation()
CometChat.Conversation | null
Returns the current active conversation, or null if no conversation is active.
getActiveChatEntity()
CometChat.User | CometChat.Group | null
Returns whichever entity is currently active (user takes precedence). Returns null if neither is active.
ChatStateService enforces that only one chat entity — a CometChat.User or a CometChat.Group — can be active at any given time:
Calling setActiveUser(user) with a non-null value automatically sets activeGroup to null.
Calling setActiveGroup(group) with a non-null value automatically sets activeUser to null.
Calling setActiveConversation(conversation) extracts the entity and delegates to setActiveUser() or setActiveGroup(), which applies the same rule.
Calling clearActiveChat() resets all three signals to null.
This prevents ambiguous states and ensures components always know which entity they are working with.
Setting a user clears the group, and setting a group clears the user. Design your
navigation flow with this in mind — you do not need to manually clear the previous
entity before setting a new one.
import { inject } from '@angular/core';import { ChatStateService } from '@cometchat/chat-uikit-angular';import { CometChat } from '@cometchat/chat-sdk-javascript';export class ChatNavigationComponent { private chatStateService = inject(ChatStateService); selectUser(user: CometChat.User): void { this.chatStateService.setActiveUser(user); // At this point: // activeUser() → user // activeGroup() → null (automatically cleared) } selectGroup(group: CometChat.Group): void { this.chatStateService.setActiveGroup(group); // At this point: // activeGroup() → group // activeUser() → null (automatically cleared) }}
Signals provide synchronous, fine-grained reactivity with automatic dependency tracking. This is the recommended approach for new code.
Signals are the preferred API for reading chat state. They integrate natively with
Angular’s change detection and require no manual subscription management.
Component
import { Component, inject, computed } from '@angular/core';import { ChatStateService } from '@cometchat/chat-uikit-angular';import { CometChat } from '@cometchat/chat-sdk-javascript';@Component({ selector: 'app-chat-panel', template: ` @if (activeUser()) { <span>Chatting with: {{ activeUser()!.getName() }}</span> } @if (activeGroup()) { <span>Group: {{ activeGroup()!.getName() }}</span> } <p>{{ chatLabel() }}</p> `})export class ChatPanelComponent { private chatStateService = inject(ChatStateService); activeUser = this.chatStateService.activeUser; activeGroup = this.chatStateService.activeGroup; chatLabel = computed(() => { const user = this.chatStateService.activeUser(); const group = this.chatStateService.activeGroup(); if (user) return `1:1 chat with ${user.getName()}`; if (group) return `Group: ${group.getName()}`; return 'No active chat'; }); selectUser(user: CometChat.User): void { this.chatStateService.setActiveUser(user); }}
Components can accept optional @Input() bindings that take priority over ChatStateService state. This lets you override the service for specific component instances while keeping the default wiring elsewhere.
When @Input() bindings are provided, they take priority over ChatStateService
state for that component instance. Other components continue to read from the service.
Component
Usage
import { Component, Input, inject, computed, signal } from '@angular/core';import { ChatStateService } from '@cometchat/chat-uikit-angular';import { CometChat } from '@cometchat/chat-sdk-javascript';@Component({ selector: 'app-message-header', template: ` @if (effectiveUser()) { <h3>{{ effectiveUser()!.getName() }}</h3> } `})export class MessageHeaderComponent { private chatStateService = inject(ChatStateService); /** Optional prop override — if provided, takes priority over service state. */ @Input() user?: CometChat.User; effectiveUser = computed(() => this.user ?? this.chatStateService.activeUser() );}
<!-- Service-based: component reads from ChatStateService automatically --><app-message-header /><!-- Props-based: explicit binding overrides service state --><app-message-header [user]="specificUser" />
The following Chat-Aware Components integrate with ChatStateService. Each supports the Hybrid Approach — they auto-subscribe to the service by default and accept @Input() overrides.