angular-forms

📁 7spade/black-tortoise 📅 Jan 26, 2026
4
总安装量
4
周安装量
#53009
全站排名
安装命令
npx skills add https://github.com/7spade/black-tortoise --skill angular-forms

Agent 安装分布

antigravity 3
opencode 2
windsurf 2
claude-code 2
codex 2
gemini-cli 2

Skill 文档

Angular Forms Skill

Rules

Form Creation

  • Use ReactiveFormsModule for reactive forms
  • Use FormControl for individual form fields
  • Use FormGroup to group multiple form controls
  • Use FormArray for dynamic lists of form controls
  • Use FormBuilder for simplified form creation

Validation

  • Use built-in validators: Validators.required, Validators.email, Validators.min, Validators.max, Validators.pattern
  • Custom validators MUST return ValidationErrors | null
  • Show validation errors ONLY after field is touched
  • Disable submit button when form is invalid

Form State Management

  • Check form state: valid, invalid, touched, dirty, pristine
  • Reset form using form.reset()
  • Update form values using form.patchValue() or form.setValue()

NgRx Signals Integration

  • Store form instance in signalStore state
  • Use rxMethod for async form submission
  • Use tapResponse for handling submission success/error
  • Reset form on successful submission

Form Submission

  • Use (ngSubmit) event for form submission
  • Validate form before processing: if (form.valid)
  • Handle errors with user feedback

Context

Summary

Angular Reactive Forms provide a model-driven approach to handling form inputs with built-in validation, state management, and integration with Angular’s reactive programming patterns.

When to Use This Skill

Activate this skill when you need to:

  • Create reactive forms with FormControl and FormGroup
  • Implement built-in and custom validators
  • Handle form submissions and data binding
  • Build dynamic forms with FormArray
  • Implement cross-field validation
  • Integrate forms with NgRx Signals stores
  • Handle async validators
  • Implement form state management (touched, dirty, valid)
  • Create reusable form components

Basic Reactive Form Example

import { Component } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-user-form',
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="userForm" (ngSubmit)="onSubmit()">
      <input formControlName="name" placeholder="Name">
      @if (userForm.controls.name.touched && userForm.controls.name.errors) {
        <span>Name is required</span>
      }
      
      <input formControlName="email" type="email" placeholder="Email">
      @if (userForm.controls.email.touched && userForm.controls.email.errors?.['email']) {
        <span>Invalid email</span>
      }
      
      <button type="submit" [disabled]="userForm.invalid">Submit</button>
    </form>
  `
})
export class UserFormComponent {
  userForm = new FormGroup({
    name: new FormControl('', [Validators.required]),
    email: new FormControl('', [Validators.required, Validators.email])
  });
  
  onSubmit() {
    if (this.userForm.valid) {
      console.log(this.userForm.value);
    }
  }
}

Custom Validators Example

// Custom validator function
function minAgeValidator(minAge: number): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!control.value) return null;
    
    const birthDate = new Date(control.value);
    const age = new Date().getFullYear() - birthDate.getFullYear();
    
    return age >= minAge ? null : { minAge: { required: minAge, actual: age } };
  };
}

// Usage
age: new FormControl('', [Validators.required, minAgeValidator(18)])

Integration with NgRx Signals Example

export const UserFormStore = signalStore(
  { providedIn: 'root' },
  withState({
    form: new FormGroup({
      name: new FormControl(''),
      email: new FormControl('')
    }),
    submitting: false,
    error: null as string | null
  }),
  withMethods((store, userService = inject(UserService)) => ({
    submitForm: rxMethod<void>(
      pipe(
        tap(() => patchState(store, { submitting: true })),
        switchMap(() => userService.createUser(store.form().value)),
        tapResponse({
          next: () => {
            store.form().reset();
            patchState(store, { submitting: false });
          },
          error: (error: Error) => patchState(store, { 
            error: error.message, 
            submitting: false 
          })
        })
      )
    )
  }))
);

References