Critical Patterns
Standalone Components (REQUIRED)
// ✅ ALWAYS: Use standalone components (Angular 16+)
@Component({
selector: 'app-user-card',
standalone: true,
imports: [CommonModule, RouterModule],
template: <div class="card"> <h2>{{ user.name }}</h2> </div>
})
export class UserCardComponent {
@Input({ required: true }) user!: User;
}
Signals (RECOMMENDED)
// ✅ Use signals for reactive state (Angular 16+) @Component({...}) export class CounterComponent { count = signal(0); doubleCount = computed(() => this.count() * 2);
increment() { this.count.update(n => n + 1); } }
RxJS Best Practices (REQUIRED)
// ✅ ALWAYS: Use async pipe, avoid manual subscriptions
@Component({
template: <div *ngFor="let user of users$ | async"> {{ user.name }} </div>
})
export class UsersComponent {
users$ = this.userService.getUsers();
}
// ❌ NEVER: Manual subscribe without cleanup ngOnInit() { this.userService.getUsers().subscribe(users => { this.users = users; // Memory leak risk! }); }
Decision Tree
Need component state? → Use signals Need shared state? → Use service with BehaviorSubject Need HTTP data? → Use HttpClient + async pipe Need form validation? → Use Reactive Forms Need lazy loading? → Use loadComponent()
Code Examples
Reactive Forms
@Component({...}) export class UserFormComponent { form = new FormGroup({ name: new FormControl('', [Validators.required]), email: new FormControl('', [Validators.required, Validators.email]), });
onSubmit() { if (this.form.valid) { this.userService.create(this.form.value); } } }
Service with State
@Injectable({ providedIn: 'root' }) export class CartService { private items = new BehaviorSubject<CartItem[]>([]); items$ = this.items.asObservable();
addItem(item: CartItem) { this.items.next([...this.items.value, item]); } }
Commands
ng new myapp --standalone ng serve ng generate component users ng build --configuration production ng test