angular-19

SKILL.md

When to Use

  • Implementing Angular components (detail, list, dialog)
  • Working with signals, resources, and reactive patterns
  • Creating custom pipes or directives
  • Setting up dependency injection
  • Configuring change detection strategies

Reference files (loaded on demand):


Angular 19 Key Changes

Standalone by Default (BREAKING)

All components, directives, and pipes are standalone by default. No standalone: true needed.

// ✅ Angular 19: standalone is implicit
@Component({
    selector: 'app-example',
    templateUrl: './example.component.html',
    imports: [CommonModule, MatButtonModule],
})
export class ExampleComponent {}

// ❌ Only if you NEED NgModule (legacy)
@Component({ selector: 'app-legacy', standalone: false })
export class LegacyComponent {}

Signals (Stable in v19) — Quick Reference

import { signal, computed, effect } from '@angular/core';

count = signal(0);                                    // Writable
doubleCount = computed(() => this.count() * 2);       // Derived read-only

this.count.set(5);           // Replace
this.count.update(n => n + 1); // Update
const val = this.count();    // Read

// Effect — can set signals directly in v19 (no allowSignalWrites needed)
effect(() => {
    console.log('Count:', this.count());
    this.logCount.set(this.count()); // ✅ allowed in v19
});

For full signal API (inputs, outputs, model, linkedSignal, queries) → see signals-api.md


Dependency Injection (Modern)

export class MyComponent {
    // ✅ Preferred: inject() function
    private readonly http = inject(HttpClient);
    private readonly router = inject(Router);
    private readonly logger = inject(LoggerService, { optional: true });
    private readonly config = inject(CONFIG_TOKEN, { self: true });
}

// Tree-shakable singleton
@Injectable({ providedIn: 'root' })
export class UserService {}

// ✅ New in v19: provideAppInitializer
providers: [
    provideAppInitializer(() => {
        const config = inject(ConfigService);
        return config.load();
    }),
]

RxJS Interop

import { toSignal, toObservable } from '@angular/core/rxjs-interop';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

// Observable → Signal (with custom equality in v19)
arraySignal = toSignal(this.array$, {
    initialValue: [],
    equal: (a, b) => a.length === b.length && a.every((v, i) => v === b[i]),
});

// Signal → Observable
count$ = toObservable(this.count);

// Auto-unsubscribe on destroy
this.data$.pipe(takeUntilDestroyed()).subscribe(data => { /* ... */ });

Lifecycle & Rendering (v19)

import { afterRenderEffect, afterRender, afterNextRender } from '@angular/core';

// afterRenderEffect — tracks dependencies, reruns when they change
afterRenderEffect(() => {
    const el = this.chartEl().nativeElement;
    this.renderChart(el, this.data());
});

// afterRender — every render cycle
afterRender(() => this.updateScrollPosition());

// afterNextRender — once after next render
afterNextRender(() => this.initializeThirdPartyLib());

Pipes & Directives

// Pure Pipe (default)
@Pipe({ name: 'dateFormat' })
export class DateFormatPipe implements PipeTransform {
    transform(timestamp: string, format: string): string {
        return dateFromFormat(timestamp, 'YYYY-MM-DD HH:mm:ss').format(format);
    }
}

// Attribute Directive with signal input
@Directive({ selector: '[auFocus]' })
export class FocusDirective {
    private readonly elementRef = inject(ElementRef<HTMLElement>);
    focused = input(true, { alias: 'auFocus', transform: booleanAttribute });

    constructor() {
        effect(() => {
            if (this.focused()) this.elementRef.nativeElement.focus();
        });
    }
}

Anti-Patterns

Avoid Do Instead
standalone: true (redundant in v19) Omit (standalone by default)
@Input() decorator input() / input.required()
@Output() decorator output()
@ViewChild() decorator viewChild() / viewChild.required()
allowSignalWrites in effect Not needed in v19
Manual subscription cleanup takeUntilDestroyed()
ChangeDetectionStrategy.Default Use OnPush with signals
ngOnInit for async data resource() / rxResource()
Constructor injection (verbose) inject() function
APP_INITIALIZER token provideAppInitializer()

Related Skills

Skill When to Use Together
angular-material Material components, CDK, theming
tailwind Styling with Tailwind CSS
typescript TypeScript patterns, generics, type safety
aurora-schema When working with Aurora YAML schemas

Resources

Weekly Installs
7
First Seen
Jan 31, 2026
Installed on
opencode6
gemini-cli6
github-copilot6
amp6
codex6
kimi-cli6