agentsclimarketplace

Ng22 reactivity

Skill PavanAnguluri/angular22-agent-skills/skills/ng22-reactivity

Angular 22 Agent Skills

Install
npx -y skills add PavanAnguluri/angular22-agent-skills --skill ng22-reactivity

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Enforces Angular 22 fine-grained reactivity using Signals, Signal inputs, and Model primitives.

SKILL.md

3.6 KB, as published. Nobody here has run it

Angular 22 Signals & Reactivity Discipline

You are an expert Angular 22 architect. Treat signals as the default state primitive and keep reactive dependencies explicit, synchronous, and easy to reason about.

Core Rules

  1. Use signal() for writable local state and expose readonly views with asReadonly() when consumers should not mutate the state.
  2. Use computed() for every synchronous derivation that the template or another signal depends on.
  3. Declare component inputs with input() or input.required() instead of @Input().
  4. Use model() for two-way state that must sync between parent and child.
  5. Use effect() only for side effects that talk to non-reactive APIs; prefer computed() when the output is still just data.
  6. Read signals before await boundaries. Reactive tracking is synchronous, so async gaps break dependency capture.

Signal Shapes

Writable state

import { signal } from '@angular/core';

const count = signal(0);

count.set(1);
count.update((value) => value + 1);

Readonly exposure

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

@Injectable({ providedIn: 'root' })
export class CounterState {
  private readonly _count = signal(0);
  readonly count = this._count.asReadonly();

  increment(): void {
    this._count.update((value) => value + 1);
  }
}

Dynamic derivation

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

const showCount = signal(false);
const count = signal(0);

const message = computed(() => {
  if (showCount()) {
    return `The count is ${count()}`;
  }

  return 'Nothing to see here.';
});

Component Example

import { Component, computed, input, model, signal } from '@angular/core';

@Component({
  standalone: true,
  selector: 'app-user-profile',
  template: `
    <section>
      <h3>{{ fullName() }}</h3>
      <p>{{ badgeText() }}</p>
      <input [value]="role()" (input)="role.set($any($event.target).value)" />
      <button type="button" (click)="isExpanded.update((value) => !value)">
        Toggle details
      </button>
    </section>
  `,
})
export class UserProfileComponent {
  firstName = input.required<string>();
  lastName = input.required<string>();
  role = model<string>('Developer');
  isExpanded = signal(false);

  fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
  badgeText = computed(() => (this.isExpanded() ? 'Expanded' : 'Collapsed'));
}

Effects and Interop

Use effect() when the code needs to update a non-reactive API such as storage, title, analytics, or a logging service. Use untracked() when an incidental signal read should not become a dependency.

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

effect(() => {
  const user = currentUser();

  untracked(() => loggingService.log(`User changed: ${user}`));
});

Only use toSignal() or toObservable() from @angular/core/rxjs-interop when bridging asynchronous streams such as HTTP pipelines, WebSocket feeds, or form value streams.

Anti-Patterns

  • Do not store derived data in writable state if it can be expressed as computed().
  • Do not mutate nested objects in place and expect the UI to react reliably.
  • Do not use signals as a dumping ground for unrelated state.
  • Do not call methods from templates when the result can be cached as a signal.

Review Checklist

  • Every input is signal-based.
  • Every derived value is a computed signal.
  • Side effects are isolated and intentional.
  • The template reads data, it does not calculate it.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.