| name | angular |
| description | Use when editing Angular projects, angular.json, *.component.ts files, @Component code, signals, standalone components, control-flow blocks, Angular migrations, or Angular version-specific APIs. |
Angular Framework Skill
Quick Reference
Standalone Component with Signals
import { Component, signal, computed, effect, input, output } from '@angular/core';
@Component({
selector: 'app-item-list',
standalone: true,
imports: [],
template: `
<h2>{{ title() }} ({{ count() }})</h2>
<ul>
@for (item of items(); track item.id) {
<li (click)="selectItem(item)">{{ item.name }}</li>
}
</ul>
`
})
export class ItemListComponent {
title = input.required<string>();
items = input.required<Item[]>();
itemSelected = output<Item>();
selected = signal<Item | null>(null);
count = computed(() => this.items().length);
constructor() {
effect(() => {
console.log('Selected:', this.selected());
});
}
selectItem(item: Item) {
this.selected.set(item);
this.itemSelected.emit(item);
}
}
Control Flow (Angular 17+)
@if (loading()) {
<app-spinner />
} @else if (error()) {
<app-error [message]="error()!" />
} @else {
<app-content [data]="data()" />
}
@for (item of items(); track item.id; let i = $index, first = $first) {
<div [class.first]="first">{{ i + 1 }}. {{ item.name }}</div>
} @empty {
<p>No items found</p>
}
@switch (status()) {
@case ('loading') { <app-spinner /> }
@case ('error') { <app-error /> }
@default { <app-content /> }
}
@defer (on viewport) {
<app-heavy-component />
} @loading (minimum 200ms) {
<app-skeleton />
}
Services with Inject
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
@Injectable({ providedIn: 'root' })
export class ItemService {
private http = inject(HttpClient);
items = toSignal(this.http.get<Item[]>('/api/items'), {
initialValue: []
});
async create(item: CreateItemDto): Promise<Item> {
return await firstValueFrom(
this.http.post<Item>('/api/items', item)
);
}
}
Resource API (Experimental)
## Guardrails
- Always use Standalone Components -- This is the standard for modern Angular (17+); simplifies architecture and improves tree-shaking.
- Prefer Signals for local and shared state -- Signals provide a more predictable and efficient reactivity model than observables for most UI state.
- Use
inject() instead of constructor injection -- More concise, better type inference, and works seamlessly with functional-style code.
- Verify control flow syntax -- Use
@if, @for, and @switch instead of structural directives (*ngIf, *ngFor).
resource() and httpResource() are experimental -- Use only when the project explicitly accepts experimental APIs; otherwise, use HttpClient with toSignal().
- Align to page boundaries with
@defer -- Use it to lazy load heavy or non-critical components to optimize initial bundle size.
## Validation Checkpoint