תחי ישראל - אין לנו ארץ אחרת

תחי ישראל -אין לנו ארץ אחרת

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

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

ניתן לקרוא את הגרסה האנגלית של המדריך Angular form, NgForm and two-way data binding

אחד המרכיבים החשובים ביותר בכל אפליקציה הוא טופס ה-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

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

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

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

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

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

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

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

 

 

ענה על השאלה הפשוטה הבאה כתנאי להוספת תגובה:

דג למים הוא כמו ציפור ל...?

 

תמונת המגיב

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

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

תמונת המגיב

אלי בתאריך: 10.12.2018

שמם של השדות בטופס ה-html הוא בהתאם לשם השדות במודל (name, model, hasSubroof). \r\n\r\nיש להחליף model -> motor

תמונת המגיב

Yehuda Kriv בתאריך: 01.04.2019

Good job!
perfect!!!
There are more guides like this:)

תמונת המגיב

גיטי בתאריך: 28.05.2019

אתר מדהים

תמונת המגיב

יוני בתאריך: 04.07.2019

מאמר מעולה,
נשמח גם למאמר על
reactive forms באנגולר

תמונת המגיב

שיראל בתאריך: 09.12.2019

ממש עוזר תודה

תמונת המגיב

מרים בתאריך: 26.11.2020

מאמר ברור ביותר !
אשמח לדעת איך אני יכולה לבדוק שאכן ערכי השדות תקין

תמונת המגיב

בנימין בתאריך: 18.01.2021

הדרכה פצצה

תמונת המגיב

הבי בתאריך: 11.04.2021

תודה רבה תמשיך לפרסם עוד ועוד מדריכים!!!!????

תמונת המגיב

מלכה בתאריך: 03.12.2021

מקצועי מאוד

תמונת המגיב

גג בתאריך: 27.10.2022

תודדדדדה

תמונת המגיב

הודיה בתאריך: 01.03.2023

מושלםםםםםםם!!!