{"id":"ba612bb8-625b-4329-ae25-3f837137d179","shortId":"wn7HDq","kind":"skill","title":"angular","tagline":"Modern Angular (v20+) expert with deep knowledge of Signals, Standalone Components, Zoneless applications, SSR/Hydration, and reactive patterns.","description":"# Angular Expert\n\nMaster modern Angular development with Signals, Standalone Components, Zoneless applications, SSR/Hydration, and the latest reactive patterns.\n\n## When to Use This Skill\n\n- Building new Angular applications (v20+)\n- Implementing Signals-based reactive patterns\n- Creating Standalone Components and migrating from NgModules\n- Configuring Zoneless Angular applications\n- Implementing SSR, prerendering, and hydration\n- Optimizing Angular performance\n- Adopting modern Angular patterns and best practices\n\n## Do Not Use This Skill When\n\n- Migrating from AngularJS (1.x) → use `angular-migration` skill\n- Working with legacy Angular apps that cannot upgrade\n- General TypeScript issues → use `typescript-expert` skill\n\n## Instructions\n\n1. Assess the Angular version and project structure\n2. Apply modern patterns (Signals, Standalone, Zoneless)\n3. Implement with proper typing and reactivity\n4. Validate with build and tests\n\n## Safety\n\n- Always test changes in development before production\n- Gradual migration for existing apps (don't big-bang refactor)\n- Keep backward compatibility during transitions\n\n---\n\n## Angular Version Timeline\n\n| Version        | Release | Key Features                                           |\n| -------------- | ------- | ------------------------------------------------------ |\n| **Angular 20** | Q2 2025 | Signals stable, Zoneless stable, Incremental hydration |\n| **Angular 21** | Q4 2025 | Signals-first default, Enhanced SSR                    |\n| **Angular 22** | Q2 2026 | Signal Forms, Selectorless components                  |\n\n---\n\n## 1. Signals: The New Reactive Primitive\n\nSignals are Angular's fine-grained reactivity system, replacing zone.js-based change detection.\n\n### Core Concepts\n\n```typescript\nimport { signal, computed, effect } from \"@angular/core\";\n\n// Writable signal\nconst count = signal(0);\n\n// Read value\nconsole.log(count()); // 0\n\n// Update value\ncount.set(5); // Direct set\ncount.update((v) => v + 1); // Functional update\n\n// Computed (derived) signal\nconst doubled = computed(() => count() * 2);\n\n// Effect (side effects)\neffect(() => {\n  console.log(`Count changed to: ${count()}`);\n});\n```\n\n### Signal-Based Inputs and Outputs\n\n```typescript\nimport { Component, input, output, model } from \"@angular/core\";\n\n@Component({\n  selector: \"app-user-card\",\n  standalone: true,\n  template: `\n    <div class=\"card\">\n      <h3>{{ name() }}</h3>\n      <span>{{ role() }}</span>\n      <button (click)=\"select.emit(id())\">Select</button>\n    </div>\n  `,\n})\nexport class UserCardComponent {\n  // Signal inputs (read-only)\n  id = input.required<string>();\n  name = input.required<string>();\n  role = input<string>(\"User\"); // With default\n\n  // Output\n  select = output<string>();\n\n  // Two-way binding (model)\n  isSelected = model(false);\n}\n\n// Usage:\n// <app-user-card [id]=\"'123'\" [name]=\"'John'\" [(isSelected)]=\"selected\" />\n```\n\n### Signal Queries (ViewChild/ContentChild)\n\n```typescript\nimport {\n  Component,\n  viewChild,\n  viewChildren,\n  contentChild,\n} from \"@angular/core\";\n\n@Component({\n  selector: \"app-container\",\n  standalone: true,\n  template: `\n    <input #searchInput />\n    <app-item *ngFor=\"let item of items()\" />\n  `,\n})\nexport class ContainerComponent {\n  // Signal-based queries\n  searchInput = viewChild<ElementRef>(\"searchInput\");\n  items = viewChildren(ItemComponent);\n  projectedContent = contentChild(HeaderDirective);\n\n  focusSearch() {\n    this.searchInput()?.nativeElement.focus();\n  }\n}\n```\n\n### When to Use Signals vs RxJS\n\n| Use Case                | Signals         | RxJS                             |\n| ----------------------- | --------------- | -------------------------------- |\n| Local component state   | ✅ Preferred    | Overkill                         |\n| Derived/computed values | ✅ `computed()` | `combineLatest` works            |\n| Side effects            | ✅ `effect()`   | `tap` operator                   |\n| HTTP requests           | ❌              | ✅ HttpClient returns Observable |\n| Event streams           | ❌              | ✅ `fromEvent`, operators        |\n| Complex async flows     | ❌              | ✅ `switchMap`, `mergeMap`       |\n\n---\n\n## 2. Standalone Components\n\nStandalone components are self-contained and don't require NgModule declarations.\n\n### Creating Standalone Components\n\n```typescript\nimport { Component } from \"@angular/core\";\nimport { CommonModule } from \"@angular/common\";\nimport { RouterLink } from \"@angular/router\";\n\n@Component({\n  selector: \"app-header\",\n  standalone: true,\n  imports: [CommonModule, RouterLink], // Direct imports\n  template: `\n    <header>\n      <a routerLink=\"/\">Home</a>\n      <a routerLink=\"/about\">About</a>\n    </header>\n  `,\n})\nexport class HeaderComponent {}\n```\n\n### Bootstrapping Without NgModule\n\n```typescript\n// main.ts\nimport { bootstrapApplication } from \"@angular/platform-browser\";\nimport { provideRouter } from \"@angular/router\";\nimport { provideHttpClient } from \"@angular/common/http\";\nimport { AppComponent } from \"./app/app.component\";\nimport { routes } from \"./app/app.routes\";\n\nbootstrapApplication(AppComponent, {\n  providers: [provideRouter(routes), provideHttpClient()],\n});\n```\n\n### Lazy Loading Standalone Components\n\n```typescript\n// app.routes.ts\nimport { Routes } from \"@angular/router\";\n\nexport const routes: Routes = [\n  {\n    path: \"dashboard\",\n    loadComponent: () =>\n      import(\"./dashboard/dashboard.component\").then(\n        (m) => m.DashboardComponent,\n      ),\n  },\n  {\n    path: \"admin\",\n    loadChildren: () =>\n      import(\"./admin/admin.routes\").then((m) => m.ADMIN_ROUTES),\n  },\n];\n```\n\n---\n\n## 3. Zoneless Angular\n\nZoneless applications don't use zone.js, improving performance and debugging.\n\n### Enabling Zoneless Mode\n\n```typescript\n// main.ts\nimport { bootstrapApplication } from \"@angular/platform-browser\";\nimport { provideZonelessChangeDetection } from \"@angular/core\";\nimport { AppComponent } from \"./app/app.component\";\n\nbootstrapApplication(AppComponent, {\n  providers: [provideZonelessChangeDetection()],\n});\n```\n\n### Zoneless Component Patterns\n\n```typescript\nimport { Component, signal, ChangeDetectionStrategy } from \"@angular/core\";\n\n@Component({\n  selector: \"app-counter\",\n  standalone: true,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div>Count: {{ count() }}</div>\n    <button (click)=\"increment()\">+</button>\n  `,\n})\nexport class CounterComponent {\n  count = signal(0);\n\n  increment() {\n    this.count.update((v) => v + 1);\n    // No zone.js needed - Signal triggers change detection\n  }\n}\n```\n\n### Key Zoneless Benefits\n\n- **Performance**: No zone.js patches on async APIs\n- **Debugging**: Clean stack traces without zone wrappers\n- **Bundle size**: Smaller without zone.js (~15KB savings)\n- **Interoperability**: Better with Web Components and micro-frontends\n\n---\n\n## 4. Server-Side Rendering & Hydration\n\n### SSR Setup with Angular CLI\n\n```bash\nng add @angular/ssr\n```\n\n### Hydration Configuration\n\n```typescript\n// app.config.ts\nimport { ApplicationConfig } from \"@angular/core\";\nimport {\n  provideClientHydration,\n  withEventReplay,\n} from \"@angular/platform-browser\";\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideClientHydration(withEventReplay())],\n};\n```\n\n### Incremental Hydration (v20+)\n\n```typescript\nimport { Component } from \"@angular/core\";\n\n@Component({\n  selector: \"app-page\",\n  standalone: true,\n  template: `\n    <app-hero />\n\n    @defer (hydrate on viewport) {\n      <app-comments />\n    }\n\n    @defer (hydrate on interaction) {\n      <app-chat-widget />\n    }\n  `,\n})\nexport class PageComponent {}\n```\n\n### Hydration Triggers\n\n| Trigger          | When to Use                             |\n| ---------------- | --------------------------------------- |\n| `on idle`        | Low-priority, hydrate when browser idle |\n| `on viewport`    | Hydrate when element enters viewport    |\n| `on interaction` | Hydrate on first user interaction       |\n| `on hover`       | Hydrate when user hovers                |\n| `on timer(ms)`   | Hydrate after specified delay           |\n\n---\n\n## 5. Modern Routing Patterns\n\n### Functional Route Guards\n\n```typescript\n// auth.guard.ts\nimport { inject } from \"@angular/core\";\nimport { Router, CanActivateFn } from \"@angular/router\";\nimport { AuthService } from \"./auth.service\";\n\nexport const authGuard: CanActivateFn = (route, state) => {\n  const auth = inject(AuthService);\n  const router = inject(Router);\n\n  if (auth.isAuthenticated()) {\n    return true;\n  }\n\n  return router.createUrlTree([\"/login\"], {\n    queryParams: { returnUrl: state.url },\n  });\n};\n\n// Usage in routes\nexport const routes: Routes = [\n  {\n    path: \"dashboard\",\n    loadComponent: () => import(\"./dashboard.component\"),\n    canActivate: [authGuard],\n  },\n];\n```\n\n### Route-Level Data Resolvers\n\n```typescript\nimport { inject } from '@angular/core';\nimport { ResolveFn } from '@angular/router';\nimport { UserService } from './user.service';\nimport { User } from './user.model';\n\nexport const userResolver: ResolveFn<User> = (route) => {\n  const userService = inject(UserService);\n  return userService.getUser(route.paramMap.get('id')!);\n};\n\n// In routes\n{\n  path: 'user/:id',\n  loadComponent: () => import('./user.component'),\n  resolve: { user: userResolver }\n}\n\n// In component\nexport class UserComponent {\n  private route = inject(ActivatedRoute);\n  user = toSignal(this.route.data.pipe(map(d => d['user'])));\n}\n```\n\n---\n\n## 6. Dependency Injection Patterns\n\n### Modern inject() Function\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { UserService } from './user.service';\n\n@Component({...})\nexport class UserComponent {\n  // Modern inject() - no constructor needed\n  private http = inject(HttpClient);\n  private userService = inject(UserService);\n\n  // Works in any injection context\n  users = toSignal(this.userService.getUsers());\n}\n```\n\n### Injection Tokens for Configuration\n\n```typescript\nimport { InjectionToken, inject } from \"@angular/core\";\n\n// Define token\nexport const API_BASE_URL = new InjectionToken<string>(\"API_BASE_URL\");\n\n// Provide in config\nbootstrapApplication(AppComponent, {\n  providers: [{ provide: API_BASE_URL, useValue: \"https://api.example.com\" }],\n});\n\n// Inject in service\n@Injectable({ providedIn: \"root\" })\nexport class ApiService {\n  private baseUrl = inject(API_BASE_URL);\n\n  get(endpoint: string) {\n    return this.http.get(`${this.baseUrl}/${endpoint}`);\n  }\n}\n```\n\n---\n\n## 7. Component Composition & Reusability\n\n### Content Projection (Slots)\n\n```typescript\n@Component({\n  selector: 'app-card',\n  template: `\n    <div class=\"card\">\n      <div class=\"header\">\n        <!-- Select by attribute -->\n        <ng-content select=\"[card-header]\"></ng-content>\n      </div>\n      <div class=\"body\">\n        <!-- Default slot -->\n        <ng-content></ng-content>\n      </div>\n    </div>\n  `\n})\nexport class CardComponent {}\n\n// Usage\n<app-card>\n  <h3 card-header>Title</h3>\n  <p>Body content</p>\n</app-card>\n```\n\n### Host Directives (Composition)\n\n```typescript\n// Reusable behaviors without inheritance\n@Directive({\n  standalone: true,\n  selector: '[appTooltip]',\n  inputs: ['tooltip'] // Signal input alias\n})\nexport class TooltipDirective { ... }\n\n@Component({\n  selector: 'app-button',\n  standalone: true,\n  hostDirectives: [\n    {\n      directive: TooltipDirective,\n      inputs: ['tooltip: title'] // Map input\n    }\n  ],\n  template: `<ng-content />`\n})\nexport class ButtonComponent {}\n```\n\n---\n\n## 8. State Management Patterns\n\n### Signal-Based State Service\n\n```typescript\nimport { Injectable, signal, computed } from \"@angular/core\";\n\ninterface AppState {\n  user: User | null;\n  theme: \"light\" | \"dark\";\n  notifications: Notification[];\n}\n\n@Injectable({ providedIn: \"root\" })\nexport class StateService {\n  // Private writable signals\n  private _user = signal<User | null>(null);\n  private _theme = signal<\"light\" | \"dark\">(\"light\");\n  private _notifications = signal<Notification[]>([]);\n\n  // Public read-only computed\n  readonly user = computed(() => this._user());\n  readonly theme = computed(() => this._theme());\n  readonly notifications = computed(() => this._notifications());\n  readonly unreadCount = computed(\n    () => this._notifications().filter((n) => !n.read).length,\n  );\n\n  // Actions\n  setUser(user: User | null) {\n    this._user.set(user);\n  }\n\n  toggleTheme() {\n    this._theme.update((t) => (t === \"light\" ? \"dark\" : \"light\"));\n  }\n\n  addNotification(notification: Notification) {\n    this._notifications.update((n) => [...n, notification]);\n  }\n}\n```\n\n### Component Store Pattern with Signals\n\n```typescript\nimport { Injectable, signal, computed, inject } from \"@angular/core\";\nimport { HttpClient } from \"@angular/common/http\";\nimport { toSignal } from \"@angular/core/rxjs-interop\";\n\n@Injectable()\nexport class ProductStore {\n  private http = inject(HttpClient);\n\n  // State\n  private _products = signal<Product[]>([]);\n  private _loading = signal(false);\n  private _filter = signal(\"\");\n\n  // Selectors\n  readonly products = computed(() => this._products());\n  readonly loading = computed(() => this._loading());\n  readonly filteredProducts = computed(() => {\n    const filter = this._filter().toLowerCase();\n    return this._products().filter((p) =>\n      p.name.toLowerCase().includes(filter),\n    );\n  });\n\n  // Actions\n  loadProducts() {\n    this._loading.set(true);\n    this.http.get<Product[]>(\"/api/products\").subscribe({\n      next: (products) => {\n        this._products.set(products);\n        this._loading.set(false);\n      },\n      error: () => this._loading.set(false),\n    });\n  }\n\n  setFilter(filter: string) {\n    this._filter.set(filter);\n  }\n}\n```\n\n---\n\n## 9. Forms with Signals (Coming in v22+)\n\n### Current Reactive Forms\n\n```typescript\nimport { Component, inject } from \"@angular/core\";\nimport { FormBuilder, Validators, ReactiveFormsModule } from \"@angular/forms\";\n\n@Component({\n  selector: \"app-user-form\",\n  standalone: true,\n  imports: [ReactiveFormsModule],\n  template: `\n    <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n      <input formControlName=\"name\" placeholder=\"Name\" />\n      <input formControlName=\"email\" type=\"email\" placeholder=\"Email\" />\n      <button [disabled]=\"form.invalid\">Submit</button>\n    </form>\n  `,\n})\nexport class UserFormComponent {\n  private fb = inject(FormBuilder);\n\n  form = this.fb.group({\n    name: [\"\", Validators.required],\n    email: [\"\", [Validators.required, Validators.email]],\n  });\n\n  onSubmit() {\n    if (this.form.valid) {\n      console.log(this.form.value);\n    }\n  }\n}\n```\n\n### Signal-Aware Form Patterns (Preview)\n\n```typescript\n// Future Signal Forms API (experimental)\nimport { Component, signal } from '@angular/core';\n\n@Component({...})\nexport class SignalFormComponent {\n  name = signal('');\n  email = signal('');\n\n  // Computed validation\n  isValid = computed(() =>\n    this.name().length > 0 &&\n    this.email().includes('@')\n  );\n\n  submit() {\n    if (this.isValid()) {\n      console.log({ name: this.name(), email: this.email() });\n    }\n  }\n}\n```\n\n---\n\n## 10. Performance Optimization\n\n### Change Detection Strategies\n\n```typescript\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // Only checks when:\n  // 1. Input signal/reference changes\n  // 2. Event handler runs\n  // 3. Async pipe emits\n  // 4. Signal value changes\n})\n```\n\n### Defer Blocks for Lazy Loading\n\n```typescript\n@Component({\n  template: `\n    <!-- Immediate loading -->\n    <app-header />\n\n    <!-- Lazy load when visible -->\n    @defer (on viewport) {\n      <app-heavy-chart />\n    } @placeholder {\n      <div class=\"skeleton\" />\n    } @loading (minimum 200ms) {\n      <app-spinner />\n    } @error {\n      <p>Failed to load chart</p>\n    }\n  `\n})\n```\n\n### NgOptimizedImage\n\n```typescript\nimport { NgOptimizedImage } from '@angular/common';\n\n@Component({\n  imports: [NgOptimizedImage],\n  template: `\n    <img\n      ngSrc=\"hero.jpg\"\n      width=\"800\"\n      height=\"600\"\n      priority\n    />\n\n    <img\n      ngSrc=\"thumbnail.jpg\"\n      width=\"200\"\n      height=\"150\"\n      loading=\"lazy\"\n      placeholder=\"blur\"\n    />\n  `\n})\n```\n\n---\n\n## 11. Testing Modern Angular\n\n### Testing Signal Components\n\n```typescript\nimport { ComponentFixture, TestBed } from \"@angular/core/testing\";\nimport { CounterComponent } from \"./counter.component\";\n\ndescribe(\"CounterComponent\", () => {\n  let component: CounterComponent;\n  let fixture: ComponentFixture<CounterComponent>;\n\n  beforeEach(async () => {\n    await TestBed.configureTestingModule({\n      imports: [CounterComponent], // Standalone import\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(CounterComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it(\"should increment count\", () => {\n    expect(component.count()).toBe(0);\n\n    component.increment();\n\n    expect(component.count()).toBe(1);\n  });\n\n  it(\"should update DOM on signal change\", () => {\n    component.count.set(5);\n    fixture.detectChanges();\n\n    const el = fixture.nativeElement.querySelector(\".count\");\n    expect(el.textContent).toContain(\"5\");\n  });\n});\n```\n\n### Testing with Signal Inputs\n\n```typescript\nimport { ComponentFixture, TestBed } from \"@angular/core/testing\";\nimport { ComponentRef } from \"@angular/core\";\nimport { UserCardComponent } from \"./user-card.component\";\n\ndescribe(\"UserCardComponent\", () => {\n  let fixture: ComponentFixture<UserCardComponent>;\n  let componentRef: ComponentRef<UserCardComponent>;\n\n  beforeEach(async () => {\n    await TestBed.configureTestingModule({\n      imports: [UserCardComponent],\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(UserCardComponent);\n    componentRef = fixture.componentRef;\n\n    // Set signal inputs via setInput\n    componentRef.setInput(\"id\", \"123\");\n    componentRef.setInput(\"name\", \"John Doe\");\n\n    fixture.detectChanges();\n  });\n\n  it(\"should display user name\", () => {\n    const el = fixture.nativeElement.querySelector(\"h3\");\n    expect(el.textContent).toContain(\"John Doe\");\n  });\n});\n```\n\n---\n\n## Best Practices Summary\n\n| Pattern              | ✅ Do                          | ❌ Don't                        |\n| -------------------- | ------------------------------ | ------------------------------- |\n| **State**            | Use Signals for local state    | Overuse RxJS for simple state   |\n| **Components**       | Standalone with direct imports | Bloated SharedModules           |\n| **Change Detection** | OnPush + Signals               | Default CD everywhere           |\n| **Lazy Loading**     | `@defer` and `loadComponent`   | Eager load everything           |\n| **DI**               | `inject()` function            | Constructor injection (verbose) |\n| **Inputs**           | `input()` signal function      | `@Input()` decorator (legacy)   |\n| **Zoneless**         | Enable for new projects        | Force on legacy without testing |\n\n---\n\n## Resources\n\n- [Angular.dev Documentation](https://angular.dev)\n- [Angular Signals Guide](https://angular.dev/guide/signals)\n- [Angular SSR Guide](https://angular.dev/guide/ssr)\n- [Angular Update Guide](https://angular.dev/update-guide)\n- [Angular Blog](https://blog.angular.dev)\n\n---\n\n## Common Troubleshooting\n\n| Issue                          | Solution                                            |\n| ------------------------------ | --------------------------------------------------- |\n| Signal not updating UI         | Ensure `OnPush` + call signal as function `count()` |\n| Hydration mismatch             | Check server/client content consistency             |\n| Circular dependency            | Use `inject()` with `forwardRef`                    |\n| Zoneless not detecting changes | Trigger via signal updates, not mutations           |\n| SSR fetch fails                | Use `TransferState` or `withFetch()`                |\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["angular","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity-skills"],"capabilities":["skill","source-sickn33","skill-angular","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/angular","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34964 github stars · SKILL.md body (20,210 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-25T00:50:26.169Z","embedding":null,"createdAt":"2026-04-18T21:31:00.460Z","updatedAt":"2026-04-25T00:50:26.169Z","lastSeenAt":"2026-04-25T00:50:26.169Z","tsv":"'/admin/admin.routes':528 '/api/products':1199 '/app/app.component':491,562 '/app/app.routes':495 '/auth.service':768 '/counter.component':1393 '/dashboard.component':804 '/dashboard/dashboard.component':520 '/guide/signals)':1585 '/guide/ssr)':1591 '/login':789 '/update-guide)':1597 '/user-card.component':1465 '/user.component':849 '/user.model':828 '/user.service':824,889 '0':233,238,597,1307,1424 '1':88,112,199,248,602,1331,1429 '10':1318 '11':1377 '123':332,1493 '15kb':632 '2':120,258,422,1335 '20':172 '200ms':1361 '2025':174,184 '2026':194 '21':182 '22':192 '3':127,533,1339 '4':134,643,1343 '5':242,747,1438,1447 '6':869 '7':971 '8':1032 '9':1215 'action':1108,1193 'activatedrout':861 'add':656 'addnotif':1122 'admin':525 'adopt':72 'alia':1009 'alway':141 'angular':1,3,19,23,44,62,70,74,92,98,115,164,171,181,191,207,535,652,1380,1580,1586,1592,1598 'angular-migr':91 'angular.dev':1577,1579,1584,1590,1596 'angular.dev/guide/signals)':1583 'angular.dev/guide/ssr)':1589 'angular.dev/update-guide)':1595 'angular/common':448,1372 'angular/common/http':487,885,1145 'angular/core':227,281,347,444,558,576,665,685,759,816,881,924,1047,1141,1230,1292,1461 'angular/core/rxjs-interop':1149 'angular/core/testing':1389,1457 'angular/forms':1236 'angular/platform-browser':479,554,670 'angular/router':452,483,511,764,820 'angular/ssr':657 'angularj':87 'api':619,929,934,944,961,1286 'api.example.com':948 'apiservic':957 'app':99,152,285,328,351,357,456,580,689,982,1016,1240 'app-button':1015 'app-card':981 'app-contain':350 'app-count':579 'app-head':455 'app-item':356 'app-pag':688 'app-user-card':284,327 'app-user-form':1239 'app.config.ts':661 'app.routes.ts':507 'appcompon':489,497,560,564,941 'appconfig':673 'appli':121 'applic':14,30,45,63,537 'applicationconfig':663,674 'appstat':1049 'apptooltip':1004 'ask':1678 'assess':113 'async':418,618,1340,1403,1475 'auth':776 'auth.guard.ts':755 'auth.isauthenticated':784 'authguard':771,806 'authservic':766,778 'await':1404,1476 'awar':1278 'backward':160 'bang':157 'base':50,216,270,369,930,935,945,962,1038 'baseurl':959 'bash':654 'beforeeach':1402,1474 'behavior':997 'benefit':612 'best':77,1513 'better':635 'big':156 'big-bang':155 'bind':321 'bloat':1536 'block':1348 'blog':1599 'blog.angular.dev':1600 'bodi':990 'bootstrap':471 'bootstrapappl':477,496,552,563,940 'boundari':1686 'browser':718 'build':42,137 'bundl':627 'button':293,589,1017,1253 'buttoncompon':1031 'call':1611 'canactiv':805 'canactivatefn':762,772 'cannot':101 'card':287,330,983 'cardcompon':987 'case':390 'cd':1543 'chang':143,217,265,608,1321,1334,1346,1436,1538,1631 'changedetect':584,1326 'changedetectionstrategi':574 'changedetectionstrategy.onpush':585,1327 'chart':1366 'check':1329,1618 'circular':1622 'clarif':1680 'class':299,365,469,593,703,856,892,956,986,1011,1030,1062,1152,1258,1295 'clean':621 'clear':1653 'cli':653 'click':294,590 'combinelatest':401 'come':1219 'common':1601 'commonmodul':446,461 'compat':161 'compilecompon':1410,1480 'complex':417 'compon':12,28,55,198,276,282,342,348,394,424,426,439,442,453,505,568,572,577,638,683,686,854,878,890,972,979,1013,1129,1227,1237,1289,1293,1325,1353,1373,1383,1397,1414,1531 'component.count':1422,1427 'component.count.set':1437 'component.increment':1425 'componentfixtur':1386,1401,1454,1470 'componentref':1459,1472,1473,1484 'componentref.setinput':1491,1494 'composit':973,994 'comput':224,251,256,400,1045,1087,1090,1094,1098,1102,1138,1173,1177,1181,1301,1304 'concept':220 'config':939 'configur':60,659,918 'consist':1621 'console.log':236,263,1274,1313 'const':230,254,513,672,770,775,779,797,830,834,928,1182,1440,1504 'constructor':897,1556 'contain':352,430 'containercompon':366 'content':975,991,1620 'contentchild':345,378 'context':911 'core':219 'count':231,237,257,264,267,587,588,595,1420,1443,1615 'count.set':241 'count.update':245 'counter':581 'countercompon':594,1391,1395,1398,1407,1413 'creat':53,437 'criteria':1689 'current':1222 'd':866,867 'dark':1055,1077,1120 'dashboard':517,801 'data':810 'debug':545,620 'declar':436 'decor':1564 'deep':7 'default':188,314,1542 'defer':694,698,1347,1355,1547 'defin':925 'delay':746 'depend':870,1623 'deriv':252 'derived/computed':398 'describ':1394,1466,1657 'detect':218,609,1322,1539,1630 'develop':24,145 'di':1553 'direct':243,463,993,1000,1021,1534 'disabl':1254 'display':1501 'document':1578 'doe':1497,1512 'dom':1433 'doubl':255 'eager':1550 'effect':225,259,261,262,404,405 'el':1441,1505 'el.textcontent':1445,1509 'element':724 'email':1268,1299,1316 'emit':1342 'enabl':546,1567 'endpoint':965,970 'enhanc':189 'ensur':1609 'enter':725 'environ':1669 'environment-specif':1668 'error':1207,1362 'event':413,1336 'everyth':1552 'everywher':1544 'exist':151 'expect':1421,1426,1444,1508 'experiment':1287 'expert':5,20,109,1674 'export':298,364,468,512,592,671,702,769,796,829,855,891,927,955,985,1010,1029,1061,1151,1257,1294 'fail':1363,1640 'fals':325,1166,1206,1209 'fb':1261 'featur':170 'fetch':1639 'filter':1104,1168,1183,1188,1192,1211,1214 'filteredproduct':1180 'fine':210 'fine-grain':209 'first':187,731 'fixtur':1400,1411,1469,1481 'fixture.componentinstance':1415 'fixture.componentref':1485 'fixture.detectchanges':1416,1439,1498 'fixture.nativeelement.queryselector':1442,1506 'flow':419 'focussearch':380 'forc':1571 'form':196,1216,1224,1242,1248,1250,1264,1279,1285 'form.invalid':1255 'formbuild':1232,1263 'formgroup':1249 'forwardref':1627 'fromev':415 'frontend':642 'function':249,751,875,1555,1562,1614 'futur':1283 'general':103 'get':964 'gradual':148 'grain':211 'guard':753 'guid':1582,1588,1594 'h3':1507 'handler':1337 'header':457 'headercompon':470 'headerdirect':379 'home':466 'host':992 'hostdirect':1020 'hover':735,739 'http':408,900,1155 'httpclient':410,883,902,1143,1157 'hydrat':68,180,648,658,679,695,699,705,716,722,729,736,743,1616 'id':296,306,331,841,846,1492 'idl':712,719 'implement':47,64,128 'import':222,275,341,441,445,449,460,464,476,480,484,488,492,508,519,527,551,555,559,571,662,666,682,756,760,765,803,813,817,821,825,848,877,882,886,920,1042,1135,1142,1146,1226,1231,1245,1288,1369,1374,1385,1390,1406,1409,1453,1458,1462,1478,1535 'improv':542 'includ':1191,1309 'increment':179,591,598,678,1419 'inherit':999 'inject':757,777,781,814,836,860,871,874,879,895,901,905,910,915,922,949,952,960,1043,1058,1136,1139,1150,1156,1228,1262,1554,1557,1625 'injectiontoken':921,933 'input':271,277,302,311,1005,1008,1023,1027,1332,1451,1488,1559,1560,1563,1683 'input.required':307,309 'instruct':111 'interact':701,728,733 'interfac':1048 'interoper':634 'isselect':323,335 'issu':105,1603 'isvalid':1303 'item':358,361,363,374 'itemcompon':376 'john':334,1496,1511 'keep':159 'key':169,610 'knowledg':8 'latest':34 'lazi':502,1350,1545 'legaci':97,1565,1573 'length':1107,1306 'let':360,1396,1399,1468,1471 'level':809 'light':1054,1076,1078,1119,1121 'limit':1645 'load':503,1164,1176,1351,1359,1365,1546,1551 'loadchildren':526 'loadcompon':518,802,847,1549 'loadproduct':1194 'local':393,1524 'low':714 'low-prior':713 'm':522,530 'm.admin':531 'm.dashboardcomponent':523 'main.ts':475,550 'manag':1034 'map':865,1026 'master':21 'match':1654 'mergemap':421 'micro':641 'micro-frontend':640 'migrat':57,85,93,149 'minimum':1360 'mismatch':1617 'miss':1691 'mode':548 'model':279,322,324 'modern':2,22,73,122,748,873,894,1379 'ms':742 'mutat':1637 'n':1105,1126,1127 'n.read':1106 'name':291,308,333,1266,1297,1314,1495,1503 'nativeelement.focus':382 'need':605,898 'new':43,202,932,1569 'next':1201 'ng':655 'ngfor':359 'ngmodul':59,435,473 'ngoptimizedimag':1367,1370,1375 'ngsubmit':1251 'notif':1056,1057,1080,1082,1097,1123,1124,1128 'null':1052,1071,1072,1112 'observ':412 'onpush':1540,1610 'onsubmit':1252,1271 'oper':407,416 'optim':69,1320 'output':273,278,315,317,1663 'overkil':397 'overus':1526 'p':1189 'p.name.tolowercase':1190 'page':690 'pagecompon':704 'patch':616 'path':516,524,800,844 'pattern':18,36,52,75,123,569,750,872,1035,1131,1280,1516 'perform':71,543,613,1319 'permiss':1684 'pipe':1341 'placehold':1358 'practic':78,1514 'prefer':396 'prerend':66 'preview':1281 'primit':204 'prioriti':715 'privat':858,899,903,958,1064,1067,1073,1079,1154,1159,1163,1167,1260 'product':147,1160,1162,1172,1198,1202,1204 'productstor':1153 'project':118,976,1570 'projectedcont':377 'proper':130 'provid':498,565,675,937,942,943 'provideclienthydr':667,676 'providedin':953,1059 'providehttpcli':485,501 'providerout':481,499 'providezonelesschangedetect':556,566 'public':1083 'q2':173,193 'q4':183 'queri':338,370 'queryparam':790 'reactiv':17,35,51,133,203,212,1223 'reactiveformsmodul':1234,1246 'read':234,304,1085 'read-on':303,1084 'readon':1088,1092,1096,1100,1171,1175,1179 'refactor':158 'releas':168 'render':647 'replac':214 'request':409 'requir':434,1682 'resolv':811,850 'resolvefn':818,832 'resourc':1576 'return':411,785,787,838,967,1186 'returnurl':791 'reusabl':974,996 'review':1675 'role':292,310 'root':954,1060 'rout':493,500,509,514,515,532,749,752,773,795,798,799,808,833,843,859 'route-level':807 'route.parammap.get':840 'router':761,780,782 'router.createurltree':788 'routerlink':450,462 'run':1338 'rxjs':388,392,1527 'safeti':140,1685 'save':633 'scope':1656 'searchinput':371,373 'select':297,316,336 'select.emit':295 'selector':283,349,454,578,687,980,1003,1014,1170,1238 'selectorless':197 'self':429 'self-contain':428 'server':645 'server-sid':644 'server/client':1619 'servic':951,1040 'set':244,1486 'setfilt':1210 'setinput':1490 'setup':650 'setus':1109 'sharedmodul':1537 'side':260,403,646 'signal':10,26,49,124,175,186,195,200,205,223,229,232,253,269,301,337,368,386,391,573,596,606,1007,1037,1044,1066,1069,1075,1081,1133,1137,1161,1165,1169,1218,1277,1284,1290,1298,1300,1344,1382,1435,1450,1487,1522,1541,1561,1581,1605,1612,1634 'signal-awar':1276 'signal-bas':268,367,1036 'signal/reference':1333 'signalformcompon':1296 'signals-bas':48 'signals-first':185 'simpl':1529 'size':628 'skill':41,83,94,110,1648 'skill-angular' 'slot':977 'smaller':629 'solut':1604 'source-sickn33' 'specif':1670 'specifi':745 'ssr':65,190,649,1587,1638 'ssr/hydration':15,31 'stabl':176,178 'stack':622 'standalon':11,27,54,125,288,353,423,425,438,458,504,582,691,1001,1018,1243,1408,1532 'state':395,774,1033,1039,1158,1520,1525,1530 'state.url':792 'stateservic':1063 'stop':1676 'store':1130 'strategi':1323 'stream':414 'string':966,1212 'structur':119 'submit':1256,1310 'subscrib':1200 'substitut':1666 'success':1688 'summari':1515 'switchmap':420 'system':213 'tap':406 'task':1652 'templat':290,355,465,586,693,984,1028,1247,1354,1376 'test':139,142,1378,1381,1448,1575,1672 'testb':1387,1455 'testbed.configuretestingmodule':1405,1477 'testbed.createcomponent':1412,1482 'theme':1053,1074,1093 'this._filter':1184 'this._filter.set':1213 'this._loading':1178 'this._loading.set':1195,1205,1208 'this._notifications':1099,1103 'this._notifications.update':1125 'this._products':1174,1187 'this._products.set':1203 'this._theme':1095 'this._theme.update':1116 'this._user':1091 'this._user.set':1113 'this.baseurl':969 'this.count.update':599 'this.email':1308,1317 'this.fb.group':1265 'this.form.valid':1273 'this.form.value':1275 'this.http.get':968,1197 'this.isvalid':1312 'this.name':1305,1315 'this.route.data.pipe':864 'this.searchinput':381 'this.userservice.getusers':914 'timelin':166 'timer':741 'titl':989,1025 'tobe':1423,1428 'tocontain':1446,1510 'togglethem':1115 'token':916,926 'tolowercas':1185 'tooltip':1006,1024 'tooltipdirect':1012,1022 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'tosign':863,913,1147 'trace':623 'transferst':1642 'transit':163 'treat':1661 'trigger':607,706,707,1632 'troubleshoot':1602 'true':289,354,459,583,692,786,1002,1019,1196,1244 'two':319 'two-way':318 'type':131 'typescript':104,108,221,274,340,440,474,506,549,570,660,681,754,812,876,919,978,995,1041,1134,1225,1282,1324,1352,1368,1384,1452 'typescript-expert':107 'ui':1608 'unreadcount':1101 'updat':239,250,1432,1593,1607,1635 'upgrad':102 'url':931,936,946,963 'usag':326,793,988 'use':39,81,90,106,385,389,540,710,1521,1624,1641,1646 'user':286,312,329,732,738,826,845,851,862,868,912,1050,1051,1068,1070,1089,1110,1111,1114,1241,1502 'usercardcompon':300,1463,1467,1479,1483 'usercompon':857,893 'userformcompon':1259 'userresolv':831,852 'userservic':822,835,837,887,904,906 'userservice.getuser':839 'usevalu':947 'v':246,247,600,601 'v20':4,46,680 'v22':1221 'valid':135,1233,1302,1671 'validators.email':1270 'validators.required':1267,1269 'valu':235,240,399,1345 'verbos':1558 'version':116,165,167 'via':1489,1633 'viewchild':343,372 'viewchild/contentchild':339 'viewchildren':344,375 'viewport':697,721,726,1357 'vs':387 'way':320 'web':637 'witheventreplay':668,677 'withfetch':1644 'without':472,624,630,998,1574 'work':95,402,907 'wrapper':626 'writabl':228,1065 'x':89 'zone':625 'zone.js':215,541,604,615,631 'zoneless':13,29,61,126,177,534,536,547,567,611,1566,1628","prices":[{"id":"2d19e52f-1e20-4cba-9c15-76be4efe8b3f","listingId":"ba612bb8-625b-4329-ae25-3f837137d179","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:31:00.460Z"}],"sources":[{"listingId":"ba612bb8-625b-4329-ae25-3f837137d179","source":"github","sourceId":"sickn33/antigravity-awesome-skills/angular","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular","isPrimary":false,"firstSeenAt":"2026-04-18T21:31:00.460Z","lastSeenAt":"2026-04-25T00:50:26.169Z"}],"details":{"listingId":"ba612bb8-625b-4329-ae25-3f837137d179","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"angular","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34964,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-24T06:41:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"9e74c933cdd73e362375e2176e66fee6e638046a","skill_md_path":"skills/angular/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"angular","description":"Modern Angular (v20+) expert with deep knowledge of Signals, Standalone Components, Zoneless applications, SSR/Hydration, and reactive patterns."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/angular"},"updatedAt":"2026-04-25T00:50:26.169Z"}}