[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EJ2MYQP4G38C3DNAAP4GNN":3,"skill-same:01M6EJ2MYQP4G38C3DNAAP4GNN":84},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":6,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6EJ2MYQP4G38C3DNAAP4GNN","angular-20-standalone-component",null,"Create Angular 20 standalone components using modern patterns: Signals for state management, input()\u002Foutput() functions (not decorators), @if\u002F@for\u002F@switch control flow (not *ngIf\u002F*ngFor), inject() dependency injection (not constructor), and OnPush change detection. Use this skill when scaffolding new UI components that need reactive state, form handling, or integration with services following the three-layer architecture.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002F7spade\u002Fangular-20-standalone-component\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"angular 20 standalone component","component","angular","switch","form","change detection","input","dependency injection","signals","scaffolding","three","patterns","components","dependency","injection","flow","ui","create","architecture","change","2026-11-10 10:12:30",false,"---\nname: angular-20-standalone-component\ndescription: \"Create Angular 20 standalone components using modern patterns: Signals for state management, input()\u002Foutput() functions (not decorators), @if\u002F@for\u002F@switch control flow (not *ngIf\u002F*ngFor), inject() dependency injection (not constructor), and OnPush change detection. Use this skill when scaffolding new UI components that need reactive state, form handling, or integration with services following the three-layer architecture.\"\nlicense: \"MIT\"\n---\n\n# Angular 20 Standalone Component Skill\n\nThis skill helps create Angular 20 components following modern patterns and project standards.\n\n## Core Principles\n\n### Modern Angular 20 Patterns\n- **Standalone Components**: 100% standalone, zero NgModules\n- **Signals**: Use `signal()`, `computed()`, `effect()` for state\n- **New Syntax**: `input()`, `output()`, `@if`, `@for`, `@switch`\n- **inject()**: Function-based dependency injection\n- **OnPush**: Change detection strategy for performance\n\n### Architecture Integration\n- **Presentation Layer**: Components handle UI only\n- **Service Integration**: Inject services for business logic\n- **No Direct Repository**: Never inject repositories directly\n- **Event-Driven**: Use EventBus for cross-module communication\n\n## Component Template\n\n```typescript\nimport { Component, signal, computed, effect, input, output, inject, ChangeDetectionStrategy } from '@angular\u002Fcore';\nimport { SHARED_IMPORTS } from '@shared';\nimport { YourService } from '@core\u002Fservices\u002Fyour.service';\n\n@Component({\n  selector: 'app-your-component',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    \u003Cdiv class=\"component-container\">\n      @if (loading()) {\n        \u003Cnz-spin nzSimple \u002F>\n      } @else if (hasError()) {\n        \u003Cnz-alert \n          nzType=\"error\" \n          [nzMessage]=\"errorMessage()!\"\n          nzShowIcon\n        \u002F>\n      } @else {\n        \u003Cdiv class=\"content\">\n          @for (item of items(); track item.id) {\n            \u003Capp-item-card \n              [item]=\"item\"\n              (itemChange)=\"handleItemChange($event)\"\n            \u002F>\n          } @empty {\n            \u003Cnz-empty nzNotFoundContent=\"No items found\" \u002F>\n          }\n        \u003C\u002Fdiv>\n      }\n    \u003C\u002Fdiv>\n  `,\n  styles: [`\n    .component-container {\n      padding: 24px;\n    }\n    \n    .content {\n      display: grid;\n      gap: 16px;\n    }\n  `]\n})\nexport class YourComponent {\n  \u002F\u002F ✅ Inject services with inject()\n  private yourService = inject(YourService);\n  \n  \u002F\u002F ✅ Use input() for properties (NOT @Input())\n  blueprintId = input.required\u003Cstring>();\n  readonly = input(false);\n  \n  \u002F\u002F ✅ Use output() for events (NOT @Output())\n  itemChange = output\u003CItem>();\n  \n  \u002F\u002F ✅ Use signal() for mutable state\n  loading = signal(false);\n  error = signal\u003Cstring | null>(null);\n  items = signal\u003CItem[]>([]);\n  \n  \u002F\u002F ✅ Use computed() for derived state\n  hasError = computed(() => this.error() !== null);\n  errorMessage = computed(() => this.error());\n  totalItems = computed(() => this.items().length);\n  \n  \u002F\u002F ✅ Use effect() for side effects\n  constructor() {\n    effect(() => {\n      const id = this.blueprintId();\n      console.log('Blueprint ID changed:', id);\n      this.loadItems(id);\n    });\n  }\n  \n  ngOnInit(): void {\n    this.loadItems(this.blueprintId());\n  }\n  \n  async loadItems(blueprintId: string): Promise\u003Cvoid> {\n    this.loading.set(true);\n    this.error.set(null);\n    \n    try {\n      const items = await this.yourService.getItems(blueprintId);\n      this.items.set(items);\n    } catch (err) {\n      this.error.set(err instanceof Error ? err.message : 'Unknown error');\n    } finally {\n      this.loading.set(false);\n    }\n  }\n  \n  handleItemChange(item: Item): void {\n    \u002F\u002F Update local state\n    this.items.update(items => \n      items.map(i => i.id === item.id ? item : i)\n    );\n    \n    \u002F\u002F Emit to parent\n    this.itemChange.emit(item);\n  }\n}\n```\n\n## Key Patterns\n\n### 1. Signal State Management\n\n```typescript\n\u002F\u002F Writable signals\nprivate _items = signal\u003CItem[]>([]);\n\n\u002F\u002F Read-only public access\nitems = this._items.asReadonly();\n\n\u002F\u002F Computed derived state\nfilteredItems = computed(() => \n  this._items().filter(item => item.status === 'active')\n);\n\n\u002F\u002F Update signals\nthis._items.set([...]); \u002F\u002F Replace\nthis._items.update(items => [...items, newItem]); \u002F\u002F Transform\n```\n\n### 2. Control Flow Syntax\n\n```typescript\n\u002F\u002F ✅ CORRECT: New @if syntax\n@if (condition()) {\n  \u003Cdiv>Content\u003C\u002Fdiv>\n} @else if (otherCondition()) {\n  \u003Cdiv>Other\u003C\u002Fdiv>\n} @else {\n  \u003Cdiv>Default\u003C\u002Fdiv>\n}\n\n\u002F\u002F ✅ CORRECT: New @for syntax with track\n@for (item of items(); track item.id) {\n  \u003Cdiv>{{ item.name }}\u003C\u002Fdiv>\n} @empty {\n  \u003Cp>No items\u003C\u002Fp>\n}\n\n\u002F\u002F ✅ CORRECT: New @switch syntax\n@switch (status()) {\n  @case ('active') { \u003Cspan class=\"badge-success\">Active\u003C\u002Fspan> }\n  @case ('inactive') { \u003Cspan class=\"badge-danger\">Inactive\u003C\u002Fspan> }\n  @default { \u003Cspan class=\"badge-default\">Unknown\u003C\u002Fspan> }\n}\n\n\u002F\u002F ❌ WRONG: Old syntax (forbidden)\n\u003Cdiv *ngIf=\"condition\">...\u003C\u002Fdiv>\n\u003Cdiv *ngFor=\"let item of items\">...\u003C\u002Fdiv>\n\u003Cdiv [ngSwitch]=\"status\">...\u003C\u002Fdiv>\n```\n\n### 3. Input\u002FOutput Functions\n\n```typescript\n\u002F\u002F ✅ CORRECT: Use input()\u002Foutput() functions\ntask = input.required\u003CTask>();\nreadonly = input(false);\ntaskChange = output\u003CTask>();\n\n\u002F\u002F ❌ WRONG: Decorators (forbidden)\n@Input() task!: Task;\n@Output() taskChange = new EventEmitter\u003CTask>();\n```\n\n### 4. Dependency Injection\n\n```typescript\n\u002F\u002F ✅ CORRECT: Use inject()\nprivate taskService = inject(TaskService);\nprivate router = inject(Router);\nprivate destroyRef = inject(DestroyRef);\n\n\u002F\u002F ❌ WRONG: Constructor injection (forbidden)\nconstructor(\n  private taskService: TaskService,\n  private router: Router\n) {}\n```\n\n### 5. Subscriptions\n\n```typescript\nimport { takeUntilDestroyed } from '@angular\u002Fcore\u002Frxjs-interop';\n\n\u002F\u002F ✅ CORRECT: Auto-cleanup with takeUntilDestroyed\nprivate destroyRef = inject(DestroyRef);\n\nngOnInit(): void {\n  this.service.data$\n    .pipe(takeUntilDestroyed(this.destroyRef))\n    .subscribe(data => this.items.set(data));\n}\n\n\u002F\u002F ❌ WRONG: Manual subscriptions without cleanup\nngOnInit(): void {\n  this.service.data$.subscribe(data => this.items.set(data));\n}\n```\n\n## Component Types\n\n### Smart Component (Container)\n\n```typescript\n@Component({\n  selector: 'app-task-list',\n  standalone: true,\n  imports: [SHARED_IMPORTS, TaskItemComponent],\n  template: `\n    @for (task of tasks(); track task.id) {\n      \u003Capp-task-item \n        [task]=\"task\"\n        (taskChange)=\"updateTask($event)\"\n      \u002F>\n    }\n  `\n})\nexport class TaskListComponent {\n  private taskService = inject(TaskService);\n  tasks = signal\u003CTask[]>([]);\n  \n  ngOnInit(): void {\n    this.loadTasks();\n  }\n  \n  async loadTasks(): Promise\u003Cvoid> {\n    const tasks = await this.taskService.getTasks();\n    this.tasks.set(tasks);\n  }\n  \n  async updateTask(task: Task): Promise\u003Cvoid> {\n    await this.taskService.updateTask(task.id, task);\n    this.tasks.update(tasks => \n      tasks.map(t => t.id === task.id ? task : t)\n    );\n  }\n}\n```\n\n### Presentational Component (Pure)\n\n```typescript\n@Component({\n  selector: 'app-task-item',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    \u003Cnz-card>\n      \u003Ch3>{{ task().title }}\u003C\u002Fh3>\n      \u003Cp>{{ task().description }}\u003C\u002Fp>\n      \u003Cbutton nz-button (click)=\"handleComplete()\">\n        Complete\n      \u003C\u002Fbutton>\n    \u003C\u002Fnz-card>\n  `\n})\nexport class TaskItemComponent {\n  task = input.required\u003CTask>();\n  taskChange = output\u003CTask>();\n  \n  handleComplete(): void {\n    const updated = { ...this.task(), status: 'completed' };\n    this.taskChange.emit(updated);\n  }\n}\n```\n\n## Form Handling\n\n```typescript\nimport { FormBuilder, FormGroup, Validators } from '@angular\u002Fforms';\n\n@Component({\n  selector: 'app-task-form',\n  standalone: true,\n  imports: [SHARED_IMPORTS, ReactiveFormsModule],\n  template: `\n    \u003Cform nz-form [formGroup]=\"form\" (ngSubmit)=\"handleSubmit()\">\n      \u003Cnz-form-item>\n        \u003Cnz-form-label nzRequired>Title\u003C\u002Fnz-form-label>\n        \u003Cnz-form-control nzErrorTip=\"Please enter task title\">\n          \u003Cinput nz-input formControlName=\"title\" \u002F>\n        \u003C\u002Fnz-form-control>\n      \u003C\u002Fnz-form-item>\n      \n      \u003Cbutton nz-button nzType=\"primary\" [disabled]=\"!form.valid\">\n        Submit\n      \u003C\u002Fbutton>\n    \u003C\u002Fform>\n  `\n})\nexport class TaskFormComponent {\n  private fb = inject(FormBuilder);\n  \n  form = this.fb.group({\n    title: ['', [Validators.required, Validators.maxLength(200)]],\n    description: [''],\n    status: ['pending']\n  });\n  \n  taskSubmit = output\u003CPartial\u003CTask>>();\n  \n  handleSubmit(): void {\n    if (this.form.valid) {\n      this.taskSubmit.emit(this.form.value);\n      this.form.reset();\n    }\n  }\n}\n```\n\n## Checklist\n\nWhen creating a component:\n\n- [ ] Standalone component with imports\n- [ ] Uses signal() for state\n- [ ] Uses computed() for derived state\n- [ ] Uses input()\u002Foutput() functions\n- [ ] Uses @if\u002F@for\u002F@switch syntax\n- [ ] Uses inject() for dependencies\n- [ ] OnPush change detection\n- [ ] No business logic in component\n- [ ] Proper error handling\n- [ ] Loading states\n- [ ] Empty states\n- [ ] TypeScript strict typing\n\n## References\n\n- [Angular Instructions](.github\u002Finstructions\u002Fangular.instructions.md)\n- [Signals State Management](.github\u002Finstructions\u002Fng-ng-events(GigHub)-signals-state.instructions.md)\n- [Architecture Guide](.github\u002Finstructions\u002Fng-ng-events(GigHub)-architecture.instructions.md)\n","# Angular 20 Standalone Component Skill\n\nThis skill helps create Angular 20 components following modern patterns and project standards.\n\n## Core Principles\n\n### Modern Angular 20 Patterns\n- **Standalone Components**: 100% standalone, zero NgModules\n- **Signals**: Use `signal()`, `computed()`, `effect()` for state\n- **New Syntax**: `input()`, `output()`, `@if`, `@for`, `@switch`\n- **inject()**: Function-based dependency injection\n- **OnPush**: Change detection strategy for performance\n\n### Architecture Integration\n- **Presentation Layer**: Components handle UI only\n- **Service Integration**: Inject services for business logic\n- **No Direct Repository**: Never inject repositories directly\n- **Event-Driven**: Use EventBus for cross-module communication\n\n## Component Template\n\n```typescript\nimport { Component, signal, computed, effect, input, output, inject, ChangeDetectionStrategy } from '@angular\u002Fcore';\nimport { SHARED_IMPORTS } from '@shared';\nimport { YourService } from '@core\u002Fservices\u002Fyour.service';\n\n@Component({\n  selector: 'app-your-component',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    \u003Cdiv class=\"component-container\">\n      @if (loading()) {\n        \u003Cnz-spin nzSimple \u002F>\n      } @else if (hasError()) {\n        \u003Cnz-alert \n          nzType=\"error\" \n          [nzMessage]=\"errorMessage()!\"\n          nzShowIcon\n        \u002F>\n      } @else {\n        \u003Cdiv class=\"content\">\n          @for (item of items(); track item.id) {\n            \u003Capp-item-card \n              [item]=\"item\"\n              (itemChange)=\"handleItemChange($event)\"\n            \u002F>\n          } @empty {\n            \u003Cnz-empty nzNotFoundContent=\"No items found\" \u002F>\n          }\n        \u003C\u002Fdiv>\n      }\n    \u003C\u002Fdiv>\n  `,\n  styles: [`\n    .component-container {\n      padding: 24px;\n    }\n    \n    .content {\n      display: grid;\n      gap: 16px;\n    }\n  `]\n})\nexport class YourComponent {\n  \u002F\u002F ✅ Inject services with inject()\n  private yourService = inject(YourService);\n  \n  \u002F\u002F ✅ Use input() for properties (NOT @Input())\n  blueprintId = input.required\u003Cstring>();\n  readonly = input(false);\n  \n  \u002F\u002F ✅ Use output() for events (NOT @Output())\n  itemChange = output\u003CItem>();\n  \n  \u002F\u002F ✅ Use signal() for mutable state\n  loading = signal(false);\n  error = signal\u003Cstring | null>(null);\n  items = signal\u003CItem[]>([]);\n  \n  \u002F\u002F ✅ Use computed() for derived state\n  hasError = computed(() => this.error() !== null);\n  errorMessage = computed(() => this.error());\n  totalItems = computed(() => this.items().length);\n  \n  \u002F\u002F ✅ Use effect() for side effects\n  constructor() {\n    effect(() => {\n      const id = this.blueprintId();\n      console.log('Blueprint ID changed:', id);\n      this.loadItems(id);\n    });\n  }\n  \n  ngOnInit(): void {\n    this.loadItems(this.blueprintId());\n  }\n  \n  async loadItems(blueprintId: string): Promise\u003Cvoid> {\n    this.loading.set(true);\n    this.error.set(null);\n    \n    try {\n      const items = await this.yourService.getItems(blueprintId);\n      this.items.set(items);\n    } catch (err) {\n      this.error.set(err instanceof Error ? err.message : 'Unknown error');\n    } finally {\n      this.loading.set(false);\n    }\n  }\n  \n  handleItemChange(item: Item): void {\n    \u002F\u002F Update local state\n    this.items.update(items => \n      items.map(i => i.id === item.id ? item : i)\n    );\n    \n    \u002F\u002F Emit to parent\n    this.itemChange.emit(item);\n  }\n}\n```\n\n## Key Patterns\n\n### 1. Signal State Management\n\n```typescript\n\u002F\u002F Writable signals\nprivate _items = signal\u003CItem[]>([]);\n\n\u002F\u002F Read-only public access\nitems = this._items.asReadonly();\n\n\u002F\u002F Computed derived state\nfilteredItems = computed(() => \n  this._items().filter(item => item.status === 'active')\n);\n\n\u002F\u002F Update signals\nthis._items.set([...]); \u002F\u002F Replace\nthis._items.update(items => [...items, newItem]); \u002F\u002F Transform\n```\n\n### 2. Control Flow Syntax\n\n```typescript\n\u002F\u002F ✅ CORRECT: New @if syntax\n@if (condition()) {\n  \u003Cdiv>Content\u003C\u002Fdiv>\n} @else if (otherCondition()) {\n  \u003Cdiv>Other\u003C\u002Fdiv>\n} @else {\n  \u003Cdiv>Default\u003C\u002Fdiv>\n}\n\n\u002F\u002F ✅ CORRECT: New @for syntax with track\n@for (item of items(); track item.id) {\n  \u003Cdiv>{{ item.name }}\u003C\u002Fdiv>\n} @empty {\n  \u003Cp>No items\u003C\u002Fp>\n}\n\n\u002F\u002F ✅ CORRECT: New @switch syntax\n@switch (status()) {\n  @case ('active') { \u003Cspan class=\"badge-success\">Active\u003C\u002Fspan> }\n  @case ('inactive') { \u003Cspan class=\"badge-danger\">Inactive\u003C\u002Fspan> }\n  @default { \u003Cspan class=\"badge-default\">Unknown\u003C\u002Fspan> }\n}\n\n\u002F\u002F ❌ WRONG: Old syntax (forbidden)\n\u003Cdiv *ngIf=\"condition\">...\u003C\u002Fdiv>\n\u003Cdiv *ngFor=\"let item of items\">...\u003C\u002Fdiv>\n\u003Cdiv [ngSwitch]=\"status\">...\u003C\u002Fdiv>\n```\n\n### 3. Input\u002FOutput Functions\n\n```typescript\n\u002F\u002F ✅ CORRECT: Use input()\u002Foutput() functions\ntask = input.required\u003CTask>();\nreadonly = input(false);\ntaskChange = output\u003CTask>();\n\n\u002F\u002F ❌ WRONG: Decorators (forbidden)\n@Input() task!: Task;\n@Output() taskChange = new EventEmitter\u003CTask>();\n```\n\n### 4. Dependency Injection\n\n```typescript\n\u002F\u002F ✅ CORRECT: Use inject()\nprivate taskService = inject(TaskService);\nprivate router = inject(Router);\nprivate destroyRef = inject(DestroyRef);\n\n\u002F\u002F ❌ WRONG: Constructor injection (forbidden)\nconstructor(\n  private taskService: TaskService,\n  private router: Router\n) {}\n```\n\n### 5. Subscriptions\n\n```typescript\nimport { takeUntilDestroyed } from '@angular\u002Fcore\u002Frxjs-interop';\n\n\u002F\u002F ✅ CORRECT: Auto-cleanup with takeUntilDestroyed\nprivate destroyRef = inject(DestroyRef);\n\nngOnInit(): void {\n  this.service.data$\n    .pipe(takeUntilDestroyed(this.destroyRef))\n    .subscribe(data => this.items.set(data));\n}\n\n\u002F\u002F ❌ WRONG: Manual subscriptions without cleanup\nngOnInit(): void {\n  this.service.data$.subscribe(data => this.items.set(data));\n}\n```\n\n## Component Types\n\n### Smart Component (Container)\n\n```typescript\n@Component({\n  selector: 'app-task-list',\n  standalone: true,\n  imports: [SHARED_IMPORTS, TaskItemComponent],\n  template: `\n    @for (task of tasks(); track task.id) {\n      \u003Capp-task-item \n        [task]=\"task\"\n        (taskChange)=\"updateTask($event)\"\n      \u002F>\n    }\n  `\n})\nexport class TaskListComponent {\n  private taskService = inject(TaskService);\n  tasks = signal\u003CTask[]>([]);\n  \n  ngOnInit(): void {\n    this.loadTasks();\n  }\n  \n  async loadTasks(): Promise\u003Cvoid> {\n    const tasks = await this.taskService.getTasks();\n    this.tasks.set(tasks);\n  }\n  \n  async updateTask(task: Task): Promise\u003Cvoid> {\n    await this.taskService.updateTask(task.id, task);\n    this.tasks.update(tasks => \n      tasks.map(t => t.id === task.id ? task : t)\n    );\n  }\n}\n```\n\n### Presentational Component (Pure)\n\n```typescript\n@Component({\n  selector: 'app-task-item',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    \u003Cnz-card>\n      \u003Ch3>{{ task().title }}\u003C\u002Fh3>\n      \u003Cp>{{ task().description }}\u003C\u002Fp>\n      \u003Cbutton nz-button (click)=\"handleComplete()\">\n        Complete\n      \u003C\u002Fbutton>\n    \u003C\u002Fnz-card>\n  `\n})\nexport class TaskItemComponent {\n  task = input.required\u003CTask>();\n  taskChange = output\u003CTask>();\n  \n  handleComplete(): void {\n    const updated = { ...this.task(), status: 'completed' };\n    this.taskChange.emit(updated);\n  }\n}\n```\n\n## Form Handling\n\n```typescript\nimport { FormBuilder, FormGroup, Validators } from '@angular\u002Fforms';\n\n@Component({\n  selector: 'app-task-form',\n  standalone: true,\n  imports: [SHARED_IMPORTS, ReactiveFormsModule],\n  template: `\n    \u003Cform nz-form [formGroup]=\"form\" (ngSubmit)=\"handleSubmit()\">\n      \u003Cnz-form-item>\n        \u003Cnz-form-label nzRequired>Title\u003C\u002Fnz-form-label>\n        \u003Cnz-form-control nzErrorTip=\"Please enter task title\">\n          \u003Cinput nz-input formControlName=\"title\" \u002F>\n        \u003C\u002Fnz-form-control>\n      \u003C\u002Fnz-form-item>\n      \n      \u003Cbutton nz-button nzType=\"primary\" [disabled]=\"!form.valid\">\n        Submit\n      \u003C\u002Fbutton>\n    \u003C\u002Fform>\n  `\n})\nexport class TaskFormComponent {\n  private fb = inject(FormBuilder);\n  \n  form = this.fb.group({\n    title: ['', [Validators.required, Validators.maxLength(200)]],\n    description: [''],\n    status: ['pending']\n  });\n  \n  taskSubmit = output\u003CPartial\u003CTask>>();\n  \n  handleSubmit(): void {\n    if (this.form.valid) {\n      this.taskSubmit.emit(this.form.value);\n      this.form.reset();\n    }\n  }\n}\n```\n\n## Checklist\n\nWhen creating a component:\n\n- [ ] Standalone component with imports\n- [ ] Uses signal() for state\n- [ ] Uses computed() for derived state\n- [ ] Uses input()\u002Foutput() functions\n- [ ] Uses @if\u002F@for\u002F@switch syntax\n- [ ] Uses inject() for dependencies\n- [ ] OnPush change detection\n- [ ] No business logic in component\n- [ ] Proper error handling\n- [ ] Loading states\n- [ ] Empty states\n- [ ] TypeScript strict typing\n\n## References\n\n- [Angular Instructions](.github\u002Finstructions\u002Fangular.instructions.md)\n- [Signals State Management](.github\u002Finstructions\u002Fng-ng-events(GigHub)-signals-state.instructions.md)\n- [Architecture Guide](.github\u002Finstructions\u002Fng-ng-events(GigHub)-architecture.instructions.md)\n",{"name":5,"license":15,"description":7},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002F7spade\u002Fangular-20-standalone-component",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill angular-20-standalone-component",{"tool":64,"command":65},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill angular-20-standalone-component",{"tool":67,"command":68},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill angular-20-standalone-component","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002F7spade\u002Fangular-20-standalone-component\u002FSKILL.md",true,[72,78],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"scripts\u002Findex.html","SCRIPT","脚本",5620,"https:\u002F\u002Fgithub.com\u002Fweiyuhl\u002Fjmtest\u002Fblob\u002Fmaster\u002Fapp\u002Fsrc\u002Fmain\u002Fassets\u002Fskills\u002Fquery-wikipedia\u002Fscripts\u002Findex.html",{"path":79,"resourceType":80,"resourceTypeDesc":81,"sizeBytes":82,"sourceHtmlUrl":83},"skill-report.json","REFERENCE","参考文档",12863,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002F7spade\u002Fangular-20-standalone-component\u002Fskill-report.json",[85,95,105,114,120,127],{"skillNo":86,"name":87,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":91,"publishedAt":44},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[90],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[92,93,94],"model","model hierarchy","model hierarchy skill",{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":101,"publishedAt":44},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[100],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[102,103,104],"MCP","zoom","zoom mcp",{"skillNo":106,"name":107,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":110,"publishedAt":44},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[111,112,113,103],"sdk","zoom apps sdk","apps",{"skillNo":115,"name":116,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":119,"publishedAt":44},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[116],{"skillNo":121,"name":122,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":126,"publishedAt":44},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[125],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[122],{"skillNo":128,"name":129,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":44},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[129]]