Forms custom validation

כשעושים ולידציה לשדה בטופס מקבלים קוד שאומר האם הולידציה עברה או נכשלה. הקוד הזה נמצא בתוך fieldName.errors.

כל ולידציה היא פונקציה שמקבלת control: AbstractControl ומחזירה ValidationErrors | null.

נניח שאנחנו רוצים לעשות ולידציה לשם משתמש כך שהוא מחרוזת ללא רווחים.

בתוך הקומפוננטה נשים את הפונקציה של הולידציה.

comp.ts

noSpaceAllowed(control: FormControl){
    const value = control.value;

    if(value != null && value.indexOf(' ') != -1){
      return {noSpaceAllowed: true}
    }
    return null;
}

בהגדרת שדות הטופס, נחבר את פונקצית הולידציה.

comp.ts

firstName: ['', [Validators.required, this.noSpaceAllowed]],

get firstName() {
    return this.contactForm.get('presonalDetails.firstName');
}

בטמפלט נשתמש בשדה שהגדרנו ונבדוק את הערך שהפונקציה החזירה על מנת לאתר שגיאות.

comp.html

<span *ngIf="firstName?.errors?.['noSpaceAllowed']">First name is required</span>

Async validator

אנחנו צריכים Async validator כששולחים http request. ולידטור אסינכרוני מחזיר promise או observable.

נניח שאנחנו רוצים לקבל מיילים רק עם סיומת מסויימת ויש לנו ב-DB רשימה של מיילים מותרים.

נגדיר את הפונקציה של הולידציה בתוך קובץ ה-class.

comp.ts

emailNotAllowed(control: FormControl): Promise<any> | Observable<any> {
    const response = new Promise((resolve, reject) => {
      // Timer to assimulate async action
      setTimeout(() => {
        if (control.value !== 'service@taxes.gov.il') {
          resolve({ emailNotAllowed: true });
        } else {
          resolve(null);
        }
      }, 5000);
    });
    return response;
}

הקריאה לולידטור תהיה ברשימה נפרדת מזו של הולידטורים הרגילים.

comp.ts

email: ['', [Validators.required, Validators.email], this.emailNotAllowed]

Value & status change events

אירוע ValueChange יקרה אם יהיה שינוי בערך של FormCOntrol, FormGroup או FormArray. אנחנו נרשמים לקבל את השינויים בפונקציה OnInit.

comp.ts

this.contactForm.get('message')?.valueChanges.subscribe(value => {
      console.log(value);
})

אפשר גם להאזין לשינויים שיש ב-form עצמו.

comp.ts

this.contactForm.valueChanges.subscribe(value => {
      console.log(value);
})

לכל form control יש סטטוס. אם שדה אחד הוא invalid, כל הטופס יהיה invalid. כשיש בדיקה של ולידציה, האירוע StatusChanges עולה.

אפשר לחבר את הערכים שמקבלים למשתנים ב-class ולהשתמש בהם.

comp.ts

this.contactForm.statusChanges.subscribe(value => {
      console.log(value);
})

Setting values to the form

אפשר לחבר ערכים לשדות של הטופס. המבנה של הפונקציה חייב להתאים למבנה של הטופס.

comp.ts

this.contactForm = this.formBuilder.group({
      presonalDetails: this.formBuilder.group({
        firstName: ['', [Validators.required, this.noSpaceAllowed]],
        lastName: '',
        email: ['', [Validators.required, Validators.email], this.emailNotAllowed,],
      }),
      message: '',
      subjects: new FormArray([new FormControl(null)]),
});

שימוש בפונקציה setValue:

comp.ts

this.contactForm.setValue({
      presonalDetails: {
        firstName: '',
        lastName: '',
        email: ''
      },
      message: '',
      subjects: []
})

שימוש בפונקציה patchValue להשמה חלקית של הערכים:

comp.ts

this.contactForm.patchValue({
    personalDetails: {
      firstName: ''
    }
})

אפשר לאפס טופס:

comp.ts

this.contactForm.reset({
    presonalDetails: {
      firstName: '',
      lastName: '',
      email: ''
    },
    message: 'Write your message',
    subjects: []
})