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

מחבר:
בתאריך:

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

הדוגמה במודל היא טופס שלתוכו אנחנו מזינים את הפרטים של מודל מכונית, דוגמת שם המודל, והאם יש למכונית גג נפתח.

 

1. ניצור מחלקה CarModel

נתחיל מיצירת המחלקה CarModel, שמכילה את השדות של מודל המכונית, ולצורך כך נעזר ב-CLI. לחצו על הקישור כדי ללמוד כיצד להשתמש ב-CLI באפליקציה אנגולרית.

> ng generate class CarModel
export class CarModel {
    constructor(public id   : number,
                    public name: string,
                    public motor: string,
                    public hasSunroof : boolean
    ){}
}

המחלקה מכילה את השדות אתם נעבוד בטופס. מזהה המודל (id), שם המודל, סוג המנוע, והאם המודל מצויד בגג נפתח.

 

2. נייבא את ה-FormsModule

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

app-module.ts
-----------------------

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
	AppComponent
  ],
  imports: [
	BrowserModule,
	FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

לא מספיק רק לייבא את המודול, צריך גם להוסיף אותו למערך imports.

 

3. נכתוב את הקוד שישמש את הקומפוננטה

נוסיף את הקוד הבסיסי לקובץ המחלקה של הקומפוננטה.

app.component.ts
-----------------------

import { Component } from '@angular/core';

import { CarModel } from './car-model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'car model';

  motors = ['petrol', 'electric', 'unknown'];

  carModel = new CarModel(1, '', '', false);

  submitted = false;

  onSubmit(){
    this.submitted = true;
  }

   getCurrentModel() { 
    return JSON.stringify(this.carModel); 
  }
}
  • המערך motors כולל סוגים שונים של מנועים (דלק, חשמל או לא יודע).
  • האובייקט carModel מרחיב את הקלאס CarModel, והוא ריק כרגע. כי רק התחלנו.
  • כשמגישים את הטופס המתודה onSubmit משנה את ערכו של המשתנה submitted מ-false ל-true.
  • המתודה getCurrentModel מאפשרת לנו לעקוב אחרי המידע במודל בכל רגע.

 

4. נוסיף טופס ושדות לחלק ה-html של הקומפוננטה

app.component.html
---------------------------

<form>
  <label>Name</label>
  <input name="name" required>

  <br />
  <select name="motor" required>
    <option *ngFor="let motor of motors" [value]="motor">{{motor}}</option>
  </select>

  <br />
  <label><input type="radio" name="hasSunroof" value="true">Has sunroof</label>
  <label><input type="radio" name="hasSunroof" value="false">No sunroof</label>

  <br />
  <input type="submit" value="Save">
</form>
  • נקיף את הטופס בתגיות form כדי שאנגולר יזהה את הטופס.
  • שמם של השדות בטופס ה-html הוא בהתאם לשם השדות במודל (name, model, hasSubroof).
  • את רשימת הבחירה ניצור בתוך לולאת ngFor.
  • השדות הכרחיים ולכן הוספנו להם required. זה מספיק כדי שאנגולר יטפל בולידציה של השדות.

 

5. נוסיף קשירה דו-כיוונית

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

תחביר הקשירה הדו-כיוונית הוא:

[(ngModel)]="fieldName"

כשה-fieldName הוא שמו של השדה בקוד הקומפננטה.

כדי שהקשירה תעבוד חובה להוסיף לשדה שם ייחודי.

<input type="text"   name="name"  [(ngModel)]="model.name">

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

נוסיף את הקשירה הדו-כיוונית לטופס בכך שנוסיף name ו-ngModel לכל שדה:

app.component.html
---------------------------

<form>
  <label>Name</label>
  <input name="name" [(ngModel)]="carModel.name" required>

  <br />
  <select name="motor" [(ngModel)]="carModel.motor" required>
    <option *ngFor="let motor of motors" [value]="motor">{{motor}}</option>
  </select>

  <br />
  <label><input type="radio" name="hasSunroof" [(ngModel)]="carModel.hasSunroof" [value]="true">Has sunroof</label>
  <label><input type="radio" name="hasSunroof" [(ngModel)]="carModel.hasSunroof" [value]="false">No sunroof</label>

  <br />
  <input type="submit" value="Save">
</form>

 

6. עדכון המודל בזמן אמת

נשתמש במתודה getCurrentModel כדי לעקוב אחר מצב המידע במודל. לשם כך, נשבץ קריאה לפונקציה בתוך קובץ ה-html של הקונטרולר.

app.component.html
---------------------------

<pre>{{ getCurrentModel() }}</pre>

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

הדגמה של קשירה  דו-כיוונית בטפסים של Angular

 

7. NgForm

מכיוון שייבאנו את NgForm למודול השורש של האפליקציה בצעד השני, והקפדנו שהטופס ימצא בין תגיות form, אנגולר הלביש באופן אוטומטי את הדירקטיבה NgForm על הטופס. הדירקטיבה מחזיקה את המידע בטופס, ועוקבת אחרי מצב הזנת השדות, ומצב הולידציה של השדות ושל הטופס.

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

כדי לעקוב אחר המצב של אחד השדות נוסיף עליו local reference. לדוגמה, נוסיף local reference ששמו trackName על השדה name. נדפיס את הקלאסים מיד מתחת לשדה באופן הבא:

<input type="text" name="name" [(ngModel)]="carModel.name" required #trackName>
{{trackName.className}}

נרענן את הדף, ונראה את שמות הקלאסים שאנגולר צירף לשדות:

שינוי הקלאסים בטפסים של אנגולר

ng-untouched ng-pristine ng-invalid

  • ng-untouched כי לא נגענו בשדה
  • ng-pristine כי לא שינינו את ערך השדה
  • ng-invalid כי השדה הוא שדה חובה, ועדיין לא הזנו ערך

נכנס לשדה, ונצא ממנו בלי לשנות את ערכו, ונקבל את שילוב הקלאסים הבא:

ng-pristine ng-invalid ng-touched

  • ng-pristine כי לא שינינו את ערך השדה
  • ng-invalid כי השדה הוא שדה חובה, ועדיין לא הזנו ערך
  • ng-touched כי נכנסנו לתוך השדה

נקליד מספר תווים לתוך השדה, ואילו הקלאסים שנראה:

ng-touched ng-dirty ng-valid

  • ng-touched כי נכנסנו לתוך השדה
  • ng-dirty כי שינינו את ערך השדה
  • ng-valid כי הערך עובר את הולידציה של required

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

נוסיף את ה-local reference ששמו carModelForm על התגית הפותחת של הטופס:

<form #carModelForm="ngForm">

הצבת ה-ngForm כערכו של ה-local reference שמתייחס לטופס כולו מאפשרת לנו לעקוב אחר מצב הטופס באמצעות תכונות של המודול NgForm .

לדוגמה, בואו נבדוק מה יקרה כשנוסיף את הקוד הבא לטופס, שמאזין לתכונה value של ה-NgForm:

{{carModelForm.value | json}}

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

אפשר גם לבדוק האם הטופס כולו ולידי על ידי האזנה לתכונה valid:

{{carModelForm.valid}}

מלמד אותנו האם הטופס ולידי. בהתאם לעובדה שכל השדות דרושים, נראה שכל עוד לא מילאנו את כל שלושת השדות מצב הטופס יהיה לא ולידי (ערך false). רק אחרי שנמלא את כל שלושת השדות יהפוך מצב הולידציה ל-true.

שינוי ערכי השדות בטופס ומצב הולידציה של הטופס בזמן אמת

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

 

8. אינדיקציה והוראות למשתמש בזמן אמת

נוסיף פסקה שתציג הודעת שגיאה בתנאי שהשדה ריק, ולכן אינו ולידי, כי הוא מוגדר כ-required, ורק בתנאי שנכנסנו לשדה.

<input type="text" name="name" [(ngModel)]="carModel.name" required #trackName="ngModel">
<p class="alert" *ngIf="!trackName.valid && trackName.touched">The name is required</p>

כדי שהודעות השגיאה בזמן אמת יעבדו, הוספנו את הדירקטיבה ngModel על ה-local reference, שיש לה תכונות דוגמת valid, touched, pristine שאנחנו יכולים להיעזר בהם כדי להנחות את המשתמש באופן מדוייק.

ניתן גם להוסיף כללי CSS שיגרמו לשינוי מראה הטופס לפי מצבו. לדוגמה, הוספת קו אדום סביב השדות שאינם ולידיים ובתנאי שנגעו בהם.

.ng-invalid.ng-touched:not(form)  {
  border: 1px solid red;
}

הודעות שגיאה בזמן אמת ואינדיקציות ויזואליות כשממלאים טופס אינטר-אקטיבי של Angular

 

9. הגשת הטופס

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

<form (ngSubmit)="onSubmit()" #carModelForm="ngForm">

 

10. כיצד למנוע את הגשת הטופס אם אינו ולידי

ניתן למנוע הגשת טופס שאינו ולידי באמצעות קשירת התכונה disabled של הטופס למצב הטופס שאנחנו יכולים לדעת אותו כי אנחנו משתמשים ב-local reference לטופס, carModelForm.

<input type="submit" value="Save" [disabled]="!carModelForm.form.valid">

 

11. איפוס המודל והטופס

אפשר לאפס את הטופס, כולל מחיקת התוכן שהוזן לשדות, איפוס מצב הטופס, ומחיקת השדות במודל באמצעות המתודה reset.

<form (ngSubmit)="onSubmit(); carModelForm.reset()" #carModelForm="ngForm">

בתגובה לאירוע ngSubmit יופעלו שתי מתודות. השנייה היא המתודה reset שתאפס את הטופס והמודל בתגובה להגשת הטופס.

למדריכים נוספים בסדרת ה-Angular

הוסף תגובה חדשה

 

= 5 + 8

תמונת המגיב

מיכל בתאריך: 29.05.2018

מאמר אלוף אהבתי החכמתי תודה