Reactive Forms נותנים לנו אפשרות שליטה גדולה יותר וגמישות בבניית טפסים. מבנה הטופס מוגדר בתוך קובץ ה-ts.

  1. מגדירים את הטופס בתוך קובץ ה-ts.
  2. מוסיפים ולידציות.
  3. מחברים את הגדרת הטופס לטופס ב-html.

כדי להשתמש ב-reactive forms צריך לייבא אותם ל-app module.

app.module.ts

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

הגדרת טופס Reactive Form

גם לקומפוננטה צריכים לייבא את רכיבי הטפסים.

formComponent.ts

import { FormGroup, FormControl } from '@angular/forms';

loginReactiveForm: FormGroup = new FormGroup({
    user: new FormControl(''),
    password: new FormControl(''),
});

אפשר גם לתת ערך ברירת מחדל לשדה בטופס.

formComponent.ts

category: new FormControl('Papers');

Form disable

אפשר להגדיר שדה כ-disabled.

category: new FormControl({value: 'Papers', disabled: true});

אחרי שמגדירים את הטופס צריך לחבר אותו לטופס בקובץ ה-html. נשתמש ב-ngSubmit כדי להגדיר את הפונקציה שתופעל בזמן שליחת הטופס.

formComponent.html

<div class="container">
  <h1 class="mb-4">Reactive forms</h1>
  <form [formGroup]="loginReactiveForm" (ngSubmit)="loginUser()">
    <input type="text" formControlName="user" placeholder="Enter name"/>
    <br /><br />
    <input type="password" formControlName="password" placeholder="Enter password"/>
    <br /><br />
    <button>Login</button>
  </form>
</div>

את הפונקציה נפעיל מתוך ה-class.

formComponent.ts

loginUser() {
    console.log(this.loginReactiveForm.value);
}

Form validation

כדי להשתמש בולידציות צריך לייבא אותן.

formComponent.ts

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

loginReactiveForm = new FormGroup({
    user: new FormControl('', [Validators.required]),
    password: new FormControl('', [
      Validators.required,
      Validators.minLength(6),
    ]),
});

אפשר להשתמש בולידטורים שונים כמו: required, min, max, email, minLength, maxLength.

אם שדה לא עבר את הולידציה, נרצה לשנות את העיצוב שלו כך שהשגיאה תבלוט למשתמש.

formComponent.css

input.ng-invalid.ng-touched{
…
}

כדי להראות את השגיאות נשתמש בפונקציית get לקבל את השדה של הטופס:

formComponent.ts

get user() {
    return this.loginReactiveForm.get('user');
}
get password() {
    return this.loginReactiveForm.get('password');
}

עכשיו אפשר להראות את השגיאות בטופס ה-html.

formComponent.html

<form [formGroup]="loginReactiveForm" (ngSubmit)="loginUser()">
    <input type="text" formControlName="user" placeholder="Enter name" />
    <br /><br />

    <div
      class="alert alert-danger"
      role="alert"
      *ngIf="user && user.invalid && user.touched">
      The user name is not valid.
    </div>

    <br />

    <input
      type="password"
      formControlName="password"
      placeholder="Enter password"/>

    <br /><br />

    <div
      class="alert alert-danger"
      role="alert"
      *ngIf="password && password.invalid && password.touched">
      The password is not valid.
    </div>

    <br />
    <button [disabled]="loginReactiveForm.invalid">Login</button>
</form>

Form group

אפשר לקבץ כמה שדות אחת קבוצה אחת. מגדירים container לקבוצה ושמים בתוכו את השדות הרצויים.

comp.html

<form [formGroup]="contactForm" (ngSubmit)="onContactSubmit()">
    <div formGroupName="presonalDetails">
      <input type="text" formControlName="firstName">
      <input type="text" formControlName="lastName">
      <input type="text" formControlName="email">
      <span *ngIf="!contactForm.get('presonalDetails.email')">Enter a valid email.</span> 
    </div>

    <input type="text" formControlName="message">
</form>

מבנה של טופס פשוט:

comp.ts

contactForm: FormGroup = new FormGroup({
    firstName: new FormControl(''),
    lastName: new FormControl(''),
    email: new FormControl(''),
    message: new FormControl(''),
});

מבנה של טופס עם קבוצה.

comp.ts

contactForm: FormGroup = new FormGroup({
    presonalDetails: new FormGroup({
      firstName: new FormControl(''),
      lastName: new FormControl(''),
      email: new FormControl(''),
    }),
    
    message: new FormControl(''),
});

Form array

אפשר להוסיף מערכים לטופס באנגולר על ידי FormArray. נגדיר את subjects כמערך וכל פעם כשנוסף נושא בטופס נכניס אותו לתוך המערך.

comp.ts

contactForm: FormGroup = new FormGroup({
    presonalDetails: new FormGroup({
      firstName: new FormControl(''),
      lastName: new FormControl(''),
      email: new FormControl(''),
    }),
    message: new FormControl(''),
    subjects: new FormArray([
      new FormControl(null),
    ])
});

addSubject(){
    (<FormArray>this.contactForm.get('subjects')).push(new FormControl(null));
}

comp.html

<form [formGroup]="contactForm" (ngSubmit)="onContactSubmit()">
    <div formGroupName="presonalDetails">
      <input type="text" formControlName="firstName" />
      <input type="text" formControlName="lastName" />
      <input type="text" formControlName="email" />
      <span *ngIf="!contactForm.get('presonalDetails.email')"
        >Enter a valid email.</span
      >
    </div>
    <input type="text" formControlName="message" />
    <div formArrayName="subjects">
      <ng-container
        *ngFor="let subject of contactForm.get('subjects')['controls']; index as i"
      >
        <input type="text" placeholder="add subject..." formControlName="{{ i }}"/>
      </ng-container>
      <button (click)="addSubject()">Add subject</button>
    </div>
</form>

אפשר ליצור ולידציות גם למערך.

comp.ts

(<FormArray>this.contactForm.get('subjects')).push(new FormControl(null, Validators.required));