smithery.ai

angular-core

Angular core patterns: standalone components, signals, inject, control flow, zoneless.

First seen Apr 7, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0
More metadata
author
gentleman-programming
version
1.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,480 B
  • docs SUMMARY.md 188 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Standalone Components (REQUIRED)

Components are standalone by default. Do NOT set standalone: true.

@Component({
  selector: 'app-user',
  imports: [CommonModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `...`
})
export class UserComponent {}

Input/Output Functions (REQUIRED)

// ✅ ALWAYS: Function-based
readonly user = input.required<User>();
readonly disabled = input(false);
readonly selected = output<User>();
readonly checked = model(false);  // Two-way binding

// ❌ NEVER: Decorators
@Input() user: User;
@Output() selected = new EventEmitter<User>();

Signals for State (REQUIRED)

readonly count = signal(0);
readonly doubled = computed(() => this.count() * 2);

// Update
this.count.set(5);
this.count.update(prev => prev + 1);

// Side effects
effect(() => localStorage.setItem('count', this.count().toString()));

NO Lifecycle Hooks (REQUIRED)

Signals replace lifecycle hooks. Do NOT use ngOnInit, ngOnChanges, ngOnDestroy.

// ❌ NEVER: Lifecycle hooks
ngOnInit() {
  this.loadUser();
}

ngOnChanges(changes: SimpleChanges) {
  if (changes['userId']) {
    this.loadUser();
  }
}

// ✅ ALWAYS: Signals + effect
readonly userId = input.required<string>();
readonly user = signal<User | null>(null);

private userEffect = effect(() => {
  // Runs automatically when userId() changes
  this.loadUser(this.userId());
});

// ✅ For derived data, use computed
readonly displayName = computed(() => this.user()?.name ?? 'Guest');

When to Use What

Need Use
React to input changes effect() watching the input signal
Derived/computed state computed()
Side effects (API calls, localStorage) effect()
Cleanup on destroy DestroyRef + inject()
// Cleanup example
private readonly destroyRef = inject(DestroyRef);

constructor() {
  const subscription = someObservable$.subscribe();
  this.destroyRef.onDestroy(() => subscription.unsubscribe());
}

inject() Over Constructor (REQUIRED)

// ✅ ALWAYS
private readonly http = inject(HttpClient);

// ❌ NEVER
constructor(private http: HttpClient) {}

Native Control Flow (REQUIRED)

@if (loading()) {
  <spinner />
} @else {
  @for (item of items(); track item.id) {
    <item-card [data]="item" />
  } @empty {
    <p>No items</p>
  }
}

@switch (status()) {
  @case ('active') { <span>Active</span> }
  @default { <span>Unknown</span> }
}

RxJS - Only When Needed

Signals are the default. Use RxJS ONLY for complex async operations.

Use Signals Use RxJS
Component state Combining multiple streams
Derived values Debounce/throttle
Simple async (single API call) Race conditions
Input/Output WebSockets, real-time
Complex error retry logic
// ✅ Simple API call - use signals
readonly user = signal<User | null>(null);
readonly loading = signal(false);

async loadUser(id: string) {
  this.loading.set(true);
  this.user.set(await firstValueFrom(this.http.get<User>(`/api/users/${id}`)));
  this.loading.set(false);
}

// ✅ Complex stream - use RxJS
readonly searchResults$ = this.searchTerm$.pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(term => this.http.get<Results>(`/api/search?q=${term}`))
);

// Convert to signal when needed in template
readonly searchResults = toSignal(this.searchResults$, { initialValue: [] });

Zoneless Angular (REQUIRED)

Angular is zoneless. Use provideZonelessChangeDetection().

bootstrapApplication(AppComponent, {
  providers: [provideZonelessChangeDetection()]
});

Remove ZoneJS:

npm uninstall zone.js

Remove from angular.json polyfills: zone.js and zone.js/testing.

Zoneless Requirements

  • Use OnPush change detection
  • Use signals for state (auto-notifies Angular)
  • Use AsyncPipe for observables
  • Use markForCheck() when needed

Resources