From 892857f000b2795b09ff168670841d52f7c27f02 Mon Sep 17 00:00:00 2001 From: 4gray Date: Thu, 4 Dec 2025 21:00:20 +0100 Subject: [PATCH] docs: add Angular signal-based coding standards --- CLAUDE.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 9420b3598..b885f245b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -144,6 +144,78 @@ This is an Nx monorepo with the following structure: - Same schema structure but implemented in IndexedDB - Limited by browser storage quotas +**Angular Coding Standards**: + +This project uses modern Angular signal-based APIs and patterns. **ALWAYS** use the following: + +- **Component Queries**: Use `viewChild()`, `viewChildren()`, `contentChild()`, `contentChildren()` instead of `@ViewChild`, `@ViewChildren`, `@ContentChild`, `@ContentChildren` decorators + ```typescript + // ✅ Correct - Signal-based + readonly menu = viewChild.required('menuRef'); + readonly items = viewChildren('item'); + + // ❌ Incorrect - Old decorator syntax + @ViewChild('menuRef') menu!: MatMenu; + @ViewChildren('item') items!: QueryList; + ``` + + **Important**: When using signals in templates with properties that expect non-signal values, unwrap the signal by calling it: + ```html + + + + + + ``` + +- **Component Inputs/Outputs**: Use `input()` and `output()` functions instead of `@Input()` and `@Output()` decorators + ```typescript + // ✅ Correct - Signal-based + readonly title = input.required(); + readonly size = input(10); // with default value + readonly clicked = output(); + + // ❌ Incorrect - Old decorator syntax + @Input({ required: true }) title!: string; + @Input() size = 10; + @Output() clicked = new EventEmitter(); + ``` + +- **Reactive State**: Use signal primitives for reactive state management + ```typescript + // ✅ Use signal(), computed(), effect(), linkedSignal() + readonly count = signal(0); + readonly doubled = computed(() => this.count() * 2); + + constructor() { + effect(() => { + console.log('Count changed:', this.count()); + }); + } + ``` + +- **Host Bindings**: Use `@HostBinding()` and `@HostListener()` decorators (these don't have signal equivalents yet) + ```typescript + @HostBinding('class.active') get isActive() { return this.active(); } + @HostListener('click') onClick() { /* ... */ } + ``` + +- **Control Flow**: Use `@if`, `@for`, `@switch` instead of `*ngIf`, `*ngFor`, `*ngSwitch` + ```typescript + // ✅ Correct - Modern syntax + @if (isLoggedIn()) { +

Welcome!

+ } + + @for (item of items(); track item.id) { +
  • {{ item.name }}
  • + } + + // ❌ Incorrect - Old syntax +

    Welcome!

    +
  • {{ item.name }}
  • + ``` + ### Backend Architecture (Electron) **Main Entry**: `apps/electron-backend/src/main.ts`