מדריך 2: httpClient באנגולר - post
לגרסתו האנגלית של המדריך Angular app with PHP backend: part 2 (POST).
מדריך זה הוא השני בסדרת המדריכים שמלמדת כיצד להשתמש ב-httpClient של Angular כדי לתקשר ב-AJAX עם צד השרת של האפליקציה. במדריך נפתח טופס אנגולרי שלתוכו יזינו המשתמשים את שם הדגם של מכונית ואת מחירה, ונשלח את המידע באמצעות POST לצד השרת.
מדריכים נוספים בסדרת httpClient
להורדת קוד האנגולר אותו נפתח במדריך
1. עבודה עם טפסים - ייבוא התלויות
כדי לעבוד עם טפסים נייבא את המודול FormsModule למודול השורש של האפליקציה:
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
// After the BrowserModule
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
וגם נוסיף את התלות NgForm לרשימת התלויות של הקומפננטה:
src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Car } from './car';
import { CarService } from './car.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
constructor(private carService: CarService) {}
ngOnInit() {
this.getCars();
}
getCars(): void {
this.carService.getAll().subscribe(
(data: Car[]) => {
this.cars = data;
this.success = 'Success in retrieving the list';
},
(err) => {
console.log(err);
this.error = err.message;
}
);
}
}
2. ה-service
ל-service, שהתחלנו לפתח במדריך הקודם, נוסיף את המתודה store שקולטת את המידע מהקומפוננטה, ומשדרת אותו לצד השרת.
src/app/car.service.ts
store(car: Car) {
return this.http.post(`${this.baseUrl}/store`, { data: car }).pipe(
map((res: any) => {
return res['data'];
})
);
}
- המתודה שמשמשת לשידור המידע לצד השרת היא post שמקבלת את נתיב ה-url בתור פרמטר ראשון וגם את האובייקט car שמכיל את המידע שהתקבל מהקומפוננטה.
- המידע שמוחזר מצד השרת כולל את כל המידע על המכונית החדשה שיצרנו (שם, מחיר, id) או שגיאה. מהתגובה המוחזרת צריך למצות את המידע הרלוונטי.
זה הקוד המלא של ה-service:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Car } from './car';
@Injectable({
providedIn: 'root',
})
export class CarService {
baseUrl = 'http ://localhost/api/';
constructor(private http : HttpClient) {}
getAll() {
return this.http.get(`${this.baseUrl}list`).pipe(
map((res: any) => {
return res['data'];
})
);
}
store(car: Car) {
return this.http.post(`${this.baseUrl}/store`, { data: car }).pipe(
map((res: any) => {
return res['data'];
})
);
}
}
3. קוד הקומפוננטה
במדריך הקודם פיתחנו את המתודה getCars שמביאה את רשימת המכוניות. במדריך זה, נוסיף לקומפוננטה את המשתנים error ו-success, שיקלטו את הודעות השגיאה וההצלחה.
src/app/app.component.ts
error = '';
success = '';
נאתחל את הטופס באמצעות אתחול האובייקט car:
car: Car = {model:'', price:0};
שמיישם את ה-interface Car אותו הגדרנו במדריך הקודם בסדרת Angular HttpClient:
src/app/car.ts
export interface Car {
model: string;
price: number;
id?: number;
}
נוסיף לקוד הקומפוננטה את המתודה addCar שקולטת את הערכים שמוזנים לטופס, ושולחת את הערכים ל-service.
addCar(f: NgForm) {
this.resetAlerts();
this.carService.store(this.car).subscribe(
(res: Car) => {
// Update the list of cars
this.cars.push(res)
// Inform the user
this.success = 'Created successfully';
// Reset the form
f.reset();
},
(err) => (this.error = err.message)
);
}
במקרה של הצלחה, מופעלת המתודה reset, שמאתחלת את הטופס.
המתודה נרשמת למתודה store של ה-service , ושולחת לו את הערכים שהמשתמשים הזינו לטופס.
ההרשמה מתבצעת באמצעות subscribe בגלל שהמתודה store היא observable.
הצפי הוא לאחת משתי אפשרויות של מידע שיוחזר מה- observable:
- במקרה הראשון, הצלחה. עליה נדווח למשתמש הקצה וגם ננקה את הטופס מערכים ונוטיפיקציות
- במקרה השני, שגיאה. אותה האפליקציה מציגה למשתמש.
הקוד המלא של הקומפוננטה:
src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Car } from './car';
import { CarService } from './car.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
cars: Car[] = [];
car: Car = {model:'', price:0};
error = '';
success = '';
constructor(private carService: CarService) {}
ngOnInit() {
this.getCars();
}
getCars(): void {
this.carService.getAll().subscribe(
(data: Car[]) => {
this.cars = data;
this.success = 'Success in retrieving the list';
},
(err) => {
console.log(err);
this.error = err.message;
}
);
}
addCar(f: NgForm) {
this.resetAlerts();
this.carService.store(this.car).subscribe(
(res: Car) => {
// Update the list of cars
this.cars.push(res)
// Inform the user
this.success = 'Created successfully';
// Reset the form
f.reset();
},
(err) => (this.error = err.message)
);
}
resetAlerts() {
this.error = '';
this.success = '';
}
}
4. ה-html של הטופס
את הטופס נוסיף מתחת לרשימה שפיתחנו ,במדריך הקודם, והוא כולל שני חלקים:
א. דיבים שמציגים את הודעות השגיאה וההצלחה, במידה והם קיימות:
src/app/app.component.html
<div class="alert alert-danger" *ngIf="error">{{error}}</div>
<div class="alert alert-success" *ngIf="success">{{success}}</div>
ב. הטופס עצמו:
src/app/app.component.html
<div id="theForm">
<h2>The form</h2>
<form #f="ngForm" name="theForm" (submit)="addCar(f)">
<div class="form-group">
<label>Model</label>
<input type="text"
class="form-control"
name="model"
[(ngModel)]="car.model"
#carModel="ngModel"
required
pattern="^[a-zA-Z ]+$">
<small class="form-text text-danger" *ngIf="carModel.errors?.required && carModel.touched">
The model name is required
</small>
<small class="form-text text-danger" *ngIf="carModel.errors?.pattern && carModel.touched">
The model name can only contain the letters a-z or A-Z
</small>
</div>
<div class="form-group">
<label>Price</label>
<input type="number"
class="form-control"
name="price"
required
[(ngModel)]="car.price"
#carPrice="ngModel">
<small class="form-text text-danger" *ngIf="carPrice.errors?.required && carPrice.touched">
The price is required
</small>
</div>
<button
class="btn btn-primary btn-sm"
[disabled]="f.invalid">Add</button>
</form>
</div>
* הטופס הוא אנגולרי, ואם לא ברור איך הוא עובד אז אני ממליץ בחום לקרוא את המדריך על טפסים אנגולריים.
- ערכי השדות בטופס קשורים בקשירה דו-כוונית לאובייקט Car אשר בקומפוננטה בעזרת ngModel.
- הוספתי כללי ולידציה לשדות, כך שבמידה והמידע שמזין המשתמש אינו תקין, השדה מקבל את הקלאס "danger".
- המשתמש יכול לשלוח את הטופס רק אם הוא מילא את כל השדות בהתאם לכללים. אם הטופס אינו ולידי, השליחה לא מתאפשרת. לדוגמה, כפתור השליחה יהיה במצב disabled.
- הגשת הטופס מעבירה את המידע מהטופס לקומפננטה באמצעות local reference של הטופס ששמו #f אשר מועבר כפרמטר לפונקציה addCar().
להורדת קוד האנגולר אותו נפתח במדריך
5. צד השרת
זה קוד ה-PHP שמטפל באחסון המידע בצד השרת:
store.php
<?php
require 'connect.php';
// Get the posted data.
$postdata = file_get_contents("php://input");
if(isset($postdata) && !empty($postdata))
{
// Extract the data.
$request = json_decode($postdata);
// Validate.
if(trim($request->data->model) === '' || (int)$request->data->price < 1)
{
return http_response_code(400);
}
// Sanitize.
$model = mysqli_real_escape_string($con, trim($request->data->model));
$price = mysqli_real_escape_string($con, (int)$request->data->price);
// Store.
$sql = "INSERT INTO `cars`(`id`,`model`,`price`) VALUES (null,'{$model}','{$price}')";
if(mysqli_query($con,$sql))
{
http_response_code(201);
$car = [
'model' => $model,
'price' => $price,
'id' => mysqli_insert_id($con)
];
echo json_encode(['data'=>$car]);
}
else
{
http_response_code(422);
}
}
במקרה של שגיאה מוחזר קוד ממשפחת ה-400.
במידה והמידע מאוחסן בהצלחה במסד הנתונים מוחזר קוד תגובה 201 וגם מערך אשר כולל את ה-id של הרשומה החדשה במסד הנתונים.
במדריך הבא נלמד כיצד לערוך את המידע.
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.