Skip to content

Latest commit

 

History

History
162 lines (146 loc) · 5.27 KB

File metadata and controls

162 lines (146 loc) · 5.27 KB
technology Angular
domain frontend
level Senior/Architect
version 20
tags
forms
data
angular
best-practices
clean-code
scalable-code
ai_role Senior Angular Data Expert
last_updated 2026-03-22

📝 Angular Data & Forms Best Practices

⬆️ Back to Top

📖 Context & Scope

  • Primary Goal: Proper implementation of data management and forms in Angular applications.
  • Target Tooling: Cursor, Windsurf, Antigravity.
  • Tech Stack Version: Angular 20

⚡ IV. Data & Forms (46-55)

⚡ 46. Template-Driven Forms without Types

Note

Context: Form Safety

❌ Bad Practice

[(ngModel)] without strict model typing.

⚠️ Problem

Risk of assigning a string to a numeric field.

✅ Best Practice

Use Reactive Forms with FormControl<string> typing or new Signal-based Forms (when out of developer preview).

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.

⚡ 47. Untyped FormGroup

Note

Context: Reactive Forms

❌ Bad Practice

const form = new FormGroup({ ... }); // Untyped

⚠️ Problem

form.value returns any.

✅ Best Practice

const form = new FormGroup<LoginForm>({
  email: new FormControl('', { nonNullable: true }),
  ...
});

🚀 Solution

Always type forms. Use nonNullable: true to avoid string | undefined hell.

⚡ 48. Subscribe inside Subscribe

Note

Context: RxJS Patterns

❌ Bad Practice

this.route.params.subscribe(params => {
  this.api.getUser(params.id).subscribe(user => ...);
});

⚠️ Problem

Classic Race Condition. If parameters change rapidly, response order is not guaranteed.

✅ Best Practice

this.route.params.pipe(
  switchMap(params => this.api.getUser(params.id))
).subscribe();

🚀 Solution

Use Flattening Operators (switchMap, concatMap, mergeMap).

⚡ 49. Ignoring AbortSignal in HTTP

Note

Context: Network Efficiency

❌ Bad Practice

Ignoring request cancellation when navigating away from the page.

⚠️ Problem

Requests continue hanging, consuming traffic.

✅ Best Practice

HttpClient automatically supports cancellation upon unsubscription. With signals: ensure rxResource or the effect correctly cancels the request.

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.

⚡ 50. Mutating Inputs directly

Note

Context: Unidirectional Data Flow

❌ Bad Practice

this.inputData.push(newItem);

⚠️ Problem

The parent component remains unaware of the change. Violates the One-Way Data Flow principle.

✅ Best Practice

Emit event (output) upwards; the parent changes the data and passes the new object downwards.

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.

⚡ 51. ngModel inside Reactive Form

Note

Context: Form Mixing

❌ Bad Practice

Using formControlName and [(ngModel)] on the same input.

⚠️ Problem

Deprecated behavior. Causes form and model synchronization conflicts.

✅ Best Practice

Use only one approach: either Reactive or Template-driven.

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.

⚡ 52. Complex Validators in Template

Note

Context: Form Logic

❌ Bad Practice

Validation via HTML attributes for complex logic.

⚠️ Problem

Hard to test, no reusability.

✅ Best Practice

Custom Validator Functions or Async Validators in the component class.

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.

⚡ 53. Forgetting updateOn: 'blur'

Note

Context: Performance

❌ Bad Practice

Validating a complex field on every keystroke (change).

⚠️ Problem

Slows down user input.

✅ Best Practice

new FormControl('', { updateOn: 'blur' });

🚀 Solution

Trigger validation/update only when the user has finished typing.

⚡ 54. Not handling API Errors

Note

Context: UX

❌ Bad Practice

.subscribe(data => ...) without an error callback.

⚠️ Problem

On a 500 error, the application "hangs" in a loading state.

✅ Best Practice

Global Error Handler or catchError in the pipe returning a safe value.

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.

⚡ 55. Hardcoded API URLs

Note

Context: Maintainability

❌ Bad Practice

http.get('https://api.com/users')

⚠️ Problem

Inability to switch environments (dev/prod).

✅ Best Practice

Using InjectionToken API_URL and environment configuration.

🚀 Solution

This approach provides a deterministic, type-safe implementation that is resilient and Agent-Readable, maintaining strict architectural boundaries.