Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions frontend/angular/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ title = input<string>('');
#### 🚀 Solution
Use Signal Inputs (`input()`). This allows Angular to precisely know *which* specific component requires an update, paving the way for Zoneless applications.

---

### 🚨 2. Using `@Output()` Decorator
**Context:** Component Outputs
#### ❌ Bad Practice
Expand All @@ -54,6 +56,8 @@ save = output<void>();
#### 🚀 Solution
Use the `output()` function. It provides strict typing, better performance, and a unified API with Signal Inputs.

---

### 🚨 3. Two-Way Binding with `@Input()` and `@Output()`
**Context:** Model Synchronization
#### ❌ Bad Practice
Expand All @@ -70,6 +74,8 @@ value = model<string>();
#### 🚀 Solution
Use `model()`. This creates a Signal that can be both read and written to, automatically synchronizing its state with the parent.

---

### 🚨 4. Structural Directives (`*ngIf`, `*ngFor`)
**Context:** Template Control Flow
#### ❌ Bad Practice
Expand All @@ -93,6 +99,8 @@ Directives require importing `CommonModule` or `NgIf/NgFor`, increasing bundle s
#### 🚀 Solution
Use the built-in Control Flow (`@if`, `@for`). It is built into the compiler, requires no imports, supports improved type-narrowing, and runs faster.

---

### 🚨 5. Subscribing in Components (Logic in `ngOnInit`)
**Context:** Data Fetching
#### ❌ Bad Practice
Expand All @@ -111,6 +119,8 @@ data = toSignal(this.service.getData());
#### 🚀 Solution
Use `toSignal()` to convert an Observable into a Signal. This automatically manages the subscription and integrates the data stream into the reactivity system.

---

### 🚨 6. `BehaviorSubject` for Local State
**Context:** Component State Management
#### ❌ Bad Practice
Expand All @@ -129,6 +139,8 @@ count = signal(0);
#### 🚀 Solution
Use `signal()` for local state. It is a primitive designed specifically for synchronizing UI and data.

---

### 🚨 7. Derived State with `ngOnChanges`
**Context:** Reactivity
#### ❌ Bad Practice
Expand All @@ -148,6 +160,8 @@ fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
#### 🚀 Solution
Use `computed()`. The signal is recalculated *only* when its dependencies change, and the result is memoized (cached).

---

### 🚨 8. Constructor Dependency Injection
**Context:** DI Pattern
#### ❌ Bad Practice
Expand All @@ -164,6 +178,8 @@ private store = inject(Store);
#### 🚀 Solution
Use the `inject()` function. It operates in the initialization context (fields or constructor), is type-safe, and does not require `super()` during inheritance.

---

### 🚨 9. Modules (`NgModule`)
**Context:** App Architecture
#### ❌ Bad Practice
Expand All @@ -186,6 +202,8 @@ Modules create an unnecessary level of indirection. Components become dependent
#### 🚀 Solution
Use Standalone Components. This is the Angular v14+ standard that makes components self-sufficient and tree-shakable.

---

### 🚨 10. String-based Route Loading
**Context:** Lazy Loading Routing
#### ❌ Bad Practice
Expand All @@ -201,6 +219,8 @@ loadComponent: () => import('./user.component').then(c => c.UserComponent)
#### 🚀 Solution
Use `loadComponent` for routing to Standalone components. This ensures minimal chunk size.

---

### 🚨 11. Heavy Logic in Templates
**Context:** Template Performance
#### ❌ Bad Practice
Expand All @@ -219,6 +239,8 @@ total = computed(() => this.calculateTotal(this.items()));
#### 🚀 Solution
Extract logic into `computed()` signals or Pure Pipes. They are only executed when input data changes.

---

### 🚨 12. Manual Subscription Management (`takeUntil`)
**Context:** RxJS Memory Leaks
#### ❌ Bad Practice
Expand All @@ -236,6 +258,8 @@ stream$.pipe(takeUntilDestroyed()).subscribe();
#### 🚀 Solution
Use the `takeUntilDestroyed()` operator. It automatically unsubscribes upon context destruction (component, directive, service).

---

### 🚨 13. Deeply Nested Components Passing Data
**Context:** Prop Drilling
#### ❌ Bad Practice
Expand All @@ -257,6 +281,8 @@ theme = inject(ThemeService).theme;
#### 🚀 Solution
Use Signal Stores or services for state sharing, or the new `input()` API with context inheritance (in the future).

---

### 🚨 14. Accessing DOM directly (`ElementRef.nativeElement`)
**Context:** Security & Abstraction
#### ❌ Bad Practice
Expand All @@ -273,6 +299,8 @@ Direct DOM access breaks abstraction (doesn't work in SSR/Web Workers) and opens
#### 🚀 Solution
Use style/class bindings or `Renderer2`. For direct manipulations, consider directives.

---

### 🚨 15. Zone.js overhead
**Context:** Change Detection
#### ❌ Bad Practice
Expand All @@ -289,12 +317,14 @@ bootstrapApplication(App, {
Migrate to Zoneless mode. Use Signals to notify Angular when a re-render is needed.

---
[⬆️ Back to Top](#)

## 📚 Specialized Topics

For further reading, please refer to the following specialized guides:

- [🏗 Architecture & Dependency Injection](./architecture.md)
- [🚀 Advanced Performance](./advanced-performance.md)
- [📦 State Management](./state-management.md)
- [📝 Data & Forms](./data-forms.md)
- [🧠 Expert/Niche Topics](./expert-niche.md)
164 changes: 164 additions & 0 deletions frontend/angular/state-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
description: Vibe coding guidelines and architectural constraints for Angular State Management, focusing on Zoneless reactivity, Signals, and modern functional APIs.
technology: Angular
domain: frontend
level: Senior/Architect
complexity: Advanced
topic: Angular State Management
vibe_coding_ready: true
last_evolution: 2026-03-28
version: "20"
tags: [state-management, signals, zoneless, angular, best-practices, clean-code, scalable-code]
ai_role: Senior Angular State Management Expert
---

> 📦 [best-practise](../../README.md) / 🖥️ [frontend](../readme.md) / 🅰️ [angular](./readme.md)

# 📦 Angular State Management: Zoneless Reactivity & Signals

# 📖 Context & Scope
- **Primary Goal:** Enforce strictly functional state management patterns using Angular 20's Zoneless architecture.
- **Target Tooling:** Cursor, Windsurf, Antigravity.
- **Tech Stack Version:** Angular 20+

> [!IMPORTANT]
> **Strict Constraints for AI:**
> - Avoid RxJS `BehaviorSubject` for local and synchronous global component state.
> - Strictly use `signal()`, `computed()`, and `effect()` to manage all dynamic data states.
> - Never use the `@Input()` and `@Output()` decorators for sharing state across component trees; rely solely on functional `input()` and `output()`.

---

## 🏗 Architecture & Data Flow

State management in Angular 20 relies entirely on the granular reactivity provided by Signals. This architecture inherently supports Zoneless change detection by exactly tracking which views need updates without relying on `zone.js`.

```mermaid
graph TD
Store[Signal Store / Global Service] -->|Signals| Comp1[Component A]
Store -->|Signals| Comp2[Component B]
Comp1 -->|input()| Child[Child Component]
Comp2 -->|model()| Child2[Two-Way Child]

classDef default fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px,color:#000;
classDef component fill:#e8f5e9,stroke:#4caf50,stroke-width:2px,color:#000;
classDef layout fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px,color:#000;

class Store layout;
class Comp1 component;
class Comp2 component;
class Child default;
class Child2 default;
```

---

## 🚀 I. Local State Management

### 🚨 1. Managing Component State with Signals
**Context:** Synchronous local state.
#### ❌ Bad Practice
```typescript
isLoading: boolean = false;
data: any[] = [];

fetchData() {
this.isLoading = true;
this.api.get().subscribe(res => {
this.data = res;
this.isLoading = false;
});
}
```
#### ⚠️ Problem
Relying on raw primitive properties means Angular relies on `zone.js` to run Change Detection globally whenever an event completes.
#### ✅ Best Practice
```typescript
isLoading = signal(false);
data = signal<Data[]>([]);

fetchData() {
this.isLoading.set(true);
this.api.get().subscribe(res => {
this.data.set(res);
this.isLoading.set(false);
});
}
```
#### 🚀 Solution
Use `signal()`. It forces the developer to explicitly use `.set()` or `.update()`, signaling to the framework exactly when and where the change occurred.

---

## ⚙️ II. Derived State

### 🚨 2. Computing Values
**Context:** Creating derived state based on other state values.
#### ❌ Bad Practice
```typescript
items = signal([1, 2, 3]);
total = 0;

updateTotal() {
this.total = this.items().reduce((a, b) => a + b, 0);
}
```
#### ⚠️ Problem
Manually syncing state variables is error-prone. If you update `items` but forget to call `updateTotal()`, the state becomes inconsistent.
#### ✅ Best Practice
```typescript
items = signal([1, 2, 3]);
total = computed(() => this.items().reduce((a, b) => a + b, 0));
```
#### 🚀 Solution
Use `computed()`. The calculated value is memoized and only re-evaluates when its specific signal dependencies (in this case, `items`) change.

---

## ⚡ III. Side Effects

### 🚨 3. Handling Side Effects Safely
**Context:** Executing logic when a signal changes.
#### ❌ Bad Practice
Using getters or Angular lifecycle hooks like `ngDoCheck` to monitor value changes and trigger side effects like logging or generic HTTP calls.
#### ⚠️ Problem
This causes severe performance degradation as the logic is run on every change detection cycle, regardless of whether the specific state actually changed.
#### ✅ Best Practice
```typescript
constructor() {
effect(() => {
console.log(`Current items count: ${this.items().length}`);
// Effect will re-run automatically only when this.items() changes.
});
}
```
#### 🚀 Solution
Use `effect()`. Effects track dependencies automatically and ensure the side effect runs solely when required. Always define them within an injection context (like a constructor).

---

## 🔗 IV. Component Communication

### 🚨 4. Modern Data Passing
**Context:** Passing data between parent and child components.
#### ❌ Bad Practice
```typescript
@Input() user: User;
@Output() userUpdate = new EventEmitter<User>();
```
#### ⚠️ Problem
Requires boilerplate, depends on decorators which are less ideal for dynamic composition, and heavily couples the components to legacy Zone-based tracking.
#### ✅ Best Practice
```typescript
// For one-way data flow
user = input.required<User>();

// For two-way data binding synchronization
userProfile = model<User>();
```
#### 🚀 Solution
Use the `input()` and `model()` functional APIs. They return signals that can be directly used in `computed()` properties within the child component.

---

[⬆️ Back to Top](#)
20 changes: 19 additions & 1 deletion frontend/javascript/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ last_updated: 2026-03-22
---
[⬆️ Back to Top](#)

## I. Fundamentals (The Basics)
## 🚀 I. Fundamentals (The Basics)

### 🚨 1. `var` vs `const/let`
**Context:** Scoping and hoisting mechanisms in modern JavaScript. `var` is function-scoped and hoisted, leading to unpredictable behavior and accidental global leakage.
Expand All @@ -41,6 +41,8 @@ console.log(price); // 100
#### 🚀 Solution
Use `const` by default to ensure immutability of the reference. Use `let` only when reassigning a variable is strictly necessary. This enforces block-level scoping and prevents accidental overrides.

---

### 🚨 2. Loose equality `==`
**Context:** JavaScript's type coercion rules are complex and often counter-intuitive.
#### ❌ Bad Practice
Expand All @@ -60,6 +62,8 @@ if (userCount === 0) {
#### 🚀 Solution
Always use strict equality `===` and inequality `!==`. This forces the developer to handle type conversions explicitly, making the code's intent clear and predictable.

---

### 🚨 3. Global Scope Pollution
**Context:** The global namespace is shared. Overwriting global properties can break third-party libraries or browser APIs.
#### ❌ Bad Practice
Expand All @@ -83,6 +87,8 @@ export const config = { api: '/v1' };
#### 🚀 Solution
Use ES Modules (`import/export`) to encapsulate code. Modules have their own scope and do not leak to the global object.

---

### 🚨 4. String concatenation vs Template Literals
**Context:** Readability and handling of multi-line strings/expressions.
#### ❌ Bad Practice
Expand All @@ -100,6 +106,8 @@ Welcome to ${siteName}.`;
#### 🚀 Solution
Use Template Literals (backticks). They allow for embedded expressions, multi-line strings, and superior readability.

---

### 🚨 5. Magic Numbers
**Context:** Numbers with no context make the codebase hard to maintain.
#### ❌ Bad Practice
Expand All @@ -121,6 +129,8 @@ if (user.age >= LEGAL_AGE) {
#### 🚀 Solution
Extract magic numbers into named constants. This provides semantic meaning and a single source of truth for configuration.

---

### 🚨 6. Boolean comparisons `(if x === true)`
**Context:** Redundancy in conditional logic.
#### ❌ Bad Practice
Expand All @@ -137,6 +147,8 @@ if (!isPending) { /* ... */ }
#### 🚀 Solution
Leverage JavaScript's truthiness/falsiness or direct boolean evaluation. It makes the code more concise and idiomatic.

---

### 🚨 7. Array/Object literal vs `new` constructor
**Context:** Object and Array instantiation.
#### ❌ Bad Practice
Expand All @@ -154,6 +166,8 @@ const map = {};
#### 🚀 Solution
Use literals `[]` and `{}`. They are visually cleaner and perform slightly better as they don't involve a function call.

---

### 🚨 8. Function length/complexity
**Context:** The Single Responsibility Principle (SRP).
#### ❌ Bad Practice
Expand All @@ -179,6 +193,8 @@ function processOrder(order) {
#### 🚀 Solution
Break functions into smaller, pure components. Aim for functions under 20 lines that do exactly one thing.

---

### 🚨 9. Deeply nested `if/else` (Arrow code)
**Context:** Cognitive load and code readability.
#### ❌ Bad Practice
Expand Down Expand Up @@ -207,6 +223,8 @@ function getData(user) {
#### 🚀 Solution
Use "Guard Clauses" to return early. This flattens the structure and handles edge cases first, leaving the happy path at the lowest nesting level.

---

### 🚨 10. Improper naming (Single letters)
**Context:** Self-documenting code.
#### ❌ Bad Practice
Expand Down
Loading
Loading