--- name: cometchat-angular-v5-placement description: "Where CometChat components go in an Angular app — the chat shell layout, thread and details panels, search, routing a chat page, and the mobile one-pane fallback. Triggers: 'add a chat page', 'put chat in my dashboard', 'conversation list beside messages', 'open a thread panel', 'chat route', 'make chat responsive'." license: "MIT" compatibility: "@cometchat/chat-uikit-angular ^5 (5.1.0–5.2.0 verified); Angular 17-21" metadata: author: "CometChat" version: "1.0.0" tags: "cometchat angular placement v5 layout routing panels responsive shell" --- > **Ground truth:** `@cometchat/chat-uikit-angular@5` (5.1.0–5.2.0 verified). Uses only components in the `angular-v5` catalog. The layouts here are built FROM the live task guides — `{DOCS_BASE}/ui-kit/angular/guides/new-chat.md`, `/guides/group-chat.md`, `/guides/threaded-messages.md`, `/guides/search-messages.md`, plus `/angular-conversation`, `/angular-one-to-one-chat`, `/angular-tab-based-chat` and `/api-reference/chat-state-service.md`; base + paths in `cometchat-angular-v5-core/references/docs-map.md`. Fetch layout-specific inputs from the component's `.md` twin rather than reading the installed bundle. **APPEND to the user's app — additive only** (`RULES.md`). ## Companion skills (read first) - `cometchat-angular-v5-core` — install, credentials, `init→login→render`, and `references/layout.md` for the sizing rules this skill assumes. - `cometchat-angular-v5-components` — which component to use and its real inputs/outputs. ## Use this skill when Deciding **where** chat lives: a dedicated route, a panel inside an existing dashboard, a widget, or the full multi-pane app. ## Pick a placement | Ask | Placement | Recipe | | --- | --- | --- | | "add chat to my app" (unscoped) | **Core surface** — list + message pane, thread and search as panels | `references/core-surface.md` | | "the whole chat app" — users, groups, calls, details | **Combined app** — tabbed selector + panels | `references/combined-app.md` | | "chat inside my dashboard" | Embed the core surface in an existing layout slot | below | | "a support widget" | Single conversation — header + list + composer, no list pane | below | Default to the **core surface** for an unscoped request. Grow to the combined app only when asked. ## Active item — use ChatStateService, not your own field Angular ships an injectable source of truth for the active chat. It exposes **signals** and **observables**; prefer signals in templates. This is what satisfies "the selected row is visually reflected" and makes panel-close round-trip correctly. ```ts import { Component, computed, inject } from '@angular/core'; import { CometChat } from '@cometchat/chat-sdk-javascript'; import { ChatStateService, CometChatUIKitConstants } from '@cometchat/chat-uikit-angular'; @Component({ selector: 'app-chat-shell', standalone: true, template: '' }) export class ChatShellComponent { readonly chatState = inject(ChatStateService); // The service's signals are `T | null`, but the kit's inputs are optional // (`T | undefined`) — bind the raw signal and Angular's strict template check // rejects it. Normalise once, here. readonly activeUser = computed(() => this.chatState.activeUser() ?? undefined); readonly activeGroup = computed(() => this.chatState.activeGroup() ?? undefined); // (itemClick) emits a Conversation — resolve the subject, then branch on its TYPE. // A Conversation has no getGuid(), so duck-typing routes groups into the user slot // and the message pane throws "getUid is not a function". See references/core-surface.md. open(conversation: CometChat.Conversation) { const subject = conversation.getConversationWith(); if (conversation.getConversationType() === CometChatUIKitConstants.MessageReceiverType.group) { this.chatState.setActiveGroup(subject as CometChat.Group); } else { this.chatState.setActiveUser(subject as CometChat.User); } } closeChat() { this.chatState.clearActiveChat(); } } ``` Available: `activeUser` `activeGroup` `activeConversation` (signals) · `activeUser$` `activeGroup$` `activeConversation$` (observables) · `setActiveUser/Group/Conversation` · `getActiveChatEntity()` · `clearActiveChat()`. Keeping a separate `selected` field alongside this is how the two drift and the list stops highlighting the open conversation. ## Panels are columns, not overlays Thread, user/group details and search are **additional columns in the same flex shell**. Opening one must not resize or remount the message list, and closing must return to the exact prior layout. ```html