מדריך 2: httpClient באנגולר - post

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

לגרסתו האנגלית של המדריך Angular app with PHP backend: part 2 (POST).

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

לחצו כדי לראות את הקוד בפעולה

להורדת קוד האנגולר אותו נפתח במדריך

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 כוכבים

 

 

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

 

= 4 + 9

תמונת המגיב

מנור בתאריך: 19.04.2020

היי בדקתי את הקוד כמה וכמה פעמים הוא לא מתקבל בסרוויס . אני עובד עם web api

תמונת המגיב

לא משנה בתאריך: 29.11.2020

הקוד טוב גם לקישור בין c# לאנגולר?

תמונת המגיב

אנונוימי בתאריך: 23.08.2021

אתה אלוףףףףףףףף
תודה על המדריך הציל אותי