Operații CRUD folosind REST API cu Angular

Scris de Bogdan Mihai Nicolae
Acest tutorial va oferi o introducere privind lucrul cu API-uri REST și Angular, acoperind conceptele și tehnicile cheie necesare pentru construirea aplicațiilor pentru a creea, citi, modifica și șterge (CREATE, READ, UPDATE și DELETE) date pe un server. Pentru a fi mai precis, vom gestiona o listă de câini pe un server. 🐶🐕🐶🐕
Instalare Nodejs (Optional) #
Săriți acestă sectiune dacă aveți Nodejs instalat pe calculator.
Pentru a instala Node.js pe Windows, puteți descărca instalatorul de pe site-ul Node.js și urmați instrucțiunile pentru a instala ultima versiune de Node.js pe sistemul dvs.
Pentru a instala Node.js pe Linux, puteți utiliza un manager de pachete precum apt-get sau yum. De exemplu, pentru a instala Node.js pe Ubuntu folosind apt-get, puteți rula următoarele comenzi:
sudo apt-get update
sudo apt-get install nodejs
Pentru a instala Node.js pe MacOS, puteți utiliza managerul de pachete Homebrew. În primul rând, va trebui să instalați Homebrew executând următoarea comandă:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
După ce Homebrew este instalat, puteți folosi pentru a instala Node.js executând următoarea comandă:
brew install node
După ce Node.js este instalat, puteți verifica instalarea executând comanda node -v, care ar trebui să afișeze versiunea instalată de Node.js. De asemenea, puteți utiliza comanda npm pentru a gestiona pachetele și dependențele pentru proiectele dumneavoastră Node.js.
Pornirea server-ului de backend #
JSON-server este o librarie bazată pe Node.js pentru crearea rapidă a unui server mock
care poate fi utilizat în scopuri de testare și dezvoltare. Este conceput să fie ușor de utilizat și configurat și oferă o modalitate simplă de a crea un API REST prin definirea datelor într-un fișier db.json.
Pentru a porni un server folosind JSON Server, va trebui să instalați pachetul JSON-server din npm
. Puteți face acest lucru rulând următoarea comandă:
npm install -g json-server
Creati un fisier db.json
avand continutul de mai jos:
{
"dogs": [
{
"id": 1,
"name": "AFFENPINSCHER",
"img": "https://images.dog.ceo/breeds/affenpinscher/n02110627_8099.jpg"
},
{
"id": 2,
"name": "AKITA",
"img": "https://images.dog.ceo//breeds//akita//An_Akita_Inu_resting.jpg"
},
{
"id": 3,
"name": "CHIHUAHUA",
"img": "https://images.dog.ceo/breeds/chihuahua/n02085620_7613.jpg"
},
{
"id": 4,
"name": "LHASA",
"img": "https://images.dog.ceo/breeds/lhasa/n02098413_7358.jpg"
},
{
"id": 5,
"name": "HOUND",
"img": "https://images.dog.ceo/breeds/hound-afghan/n02088094_2626.jpg"
}
]
}
Porniti JSON Server
folosind comanda de mai jos:
json-server --watch db.json -p 4000
Accesand link-ul http://localhost:4000/dogs/1, veti vedea:
{ "id": 1, "title": "json-server", "author": "typicode" }
Crearea aplicatiei #
Creati proiectul folosind interfata de comanda Angular CLI.
npm install -g @angular/cli
ng new my-dogs
? Do you want to enforce stricter type checking and stricter bundle budgets in the workspace?
This setting helps improve maintainability and catch bugs ahead of time.
For more information, see https://angular.io/strict No
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
cd my
cd my-dogs
ng serve
Accesand link-ul http://localhost:4200, veti vedea aplicatia noastra folosind Angular.
Adaugarea librariei Material-UI #
Material-UI este libraria de componente de la Google si putem folosi Angular CLI sa o instalam:
ng add @angular/material
Selectam optiunea "YES" la toate intrebarile in timpul instalarii.
? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink [ Preview: https://material.angular.io?theme=indigo-pink ]
? Set up global Angular Material typography styles? Yes
? Set up browser animations for Angular Material? Yes
Observam ca toate dependentele sale s-au salvat in package.json
.
Eliminarea codului inutil #
Sa inlaturam din componenta nou creata app.component.html
tot html-ul.
Aducerea datelor de la server #
Cream o noua interfata in directorul src/app
:
ng generate interface dog
unde o sa punem modelul listei de catei:
export interface Dog {
id?: number;
name: string;
img: string;
}
Cream un nou serviciu:
ng generate service `dogs`
cu toate metodele noastre CRUD:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/internal/Observable';
import { Dog } from './dog';
@Injectable({
providedIn: 'root'
})
export class DogsService {
constructor(private http: HttpClient) {
}
getDogs() {
return this.http.get('http://localhost:4000/dogs') as Observable<Dog[]>
}
addDog(postObject: Dog) {
return this.http.post('http://localhost:4000/dogs', postObject) as Observable<Dog>
}
updateDog(postObject: Dog) {
return this.http.put(`http://localhost:4000/dogs/${postObject.id}`, postObject) as Observable<Dog>
}
deleteDog(id: number) {
return this.http.delete(`http://localhost:4000/dogs/${id}`) as Observable<{}>
}
}
In componenta noastra avem nevoie de o variabila care sa stocheze aceasta lista:
...
export class AppComponent implements OnInit {
dogs: Dog[] = [];
...
Aducem lista de catei cu ajutorul unui request de tip GET
:
getDogs() {
this.dogsService.getDogs().subscribe((response) => {
this.dogs = response;
})
}
Apelam functia creata anterior in momentul in care se initializeaza componenta:
componentDidMount() {
this.getDogs()
}
Afisarea listei de catei #
Folosim tabelul dat ca exemplu in Material-UI pentru a afisa lista de catei:
<button mat-raised-button class="addButton">Add</button>
<table mat-table [dataSource]="dogs" class="mat-elevation-z8">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> </td>
</ng-container>
<ng-container matColumnDef="img">
<th mat-header-cell *matHeaderCellDef> Image </th>
<td mat-cell *matCellDef="let element"> <img class="img" [attr.src]="element.img" [attr.alt]="element.name"> </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Action </th>
<td mat-cell *matCellDef="let element">
<button class="editButton" mat-raised-button color="primary">Editare</button>
<button mat-raised-button color="primary">Stergere</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
Cream o noua variabila in componenta pentru a stoca numele coloanelor:
...
dogs: Dog[] = [];
displayedColumns: string[] = ['name', 'img', 'actions']
...
Pentru fiecare catel afisam numele, imaginea si butoanele de actiuni: Editeaza si Sterge.
Stilizarea listei de catei #
Pentru a imbunatati designul, adaugam stilurile urmatoare in app.component.css
:
.img {
height: 150px;
}
table {
width: 100%;
}
.addButton {
margin: 10px;
}
.editButton {
margin-right: 20px;
}
Stergerea unui element din lista de catei #
Stergem un element din lista de catei cu ajutorul unui request de tip DELETE
:
Adaugati in app.component.ts
metoda de stergere:
deleteDog(id: number) {
this.dogsService.deleteDog(id).subscribe(() => {
this.getDogs()
});
}
si in app.component.html
evenimentul pe buton:
<button mat-raised-button color="primary" (click)="deleteDog(element.id)">Stergere</button>
Adaugarea si editarea unui element din lista de catei #
Inseram butonul de Adaugare deasupra tabelului:
<button mat-raised-button class="addButton" (click)="addDog()">Adaugare</button>
<table mat-table [dataSource]="dogs" class="mat-elevation-z8">
...
Functia care va adauga un nou element va deschide o modala cu un formular nepopulat:
addDog() {
const dialogRef = this.dialog.open(FormComponent, {
width: '650px',
data: { name: '', img: '' }
});
dialogRef.afterClosed().subscribe(result => {
this.getDogs();
});
}
Functia care va edita un element va deschide o modala ce va contine detaliile despre catel:
editDog(dog: Dog) {
const dialogRef = this.dialog.open(FormComponent, {
width: '650px',
data: { ...dog }
});
dialogRef.afterClosed().subscribe(result => {
this.getDogs();
});
}
Cream o noua component form in directorul src/app
care va contine inputurile si logica de salvare:
ng generate component form
<div mat-dialog-content class="container">
<mat-form-field>
<input matInput [(ngModel)]="data.name" placeholder="Name">
</mat-form-field>
<mat-form-field>
<input matInput [(ngModel)]="data.img" placeholder="Image url">
</mat-form-field>
</div>
<div mat-dialog-actions>
<button mat-button (click)="closeModal()">Anulare</button>
<button mat-button cdkFocusInitial (click)="saveDog()">Save</button>
</div>
Salvam un element din lista de catei cu ajutorul metodei saveDog si a request-urilor de tip POST
si PUT
:
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import { Dog } from '../dog';
import { DogsService } from '../dogs.service';
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent {
constructor(
public dialogRef: MatDialogRef<FormComponent>,
private dogsService: DogsService,
@Inject(MAT_DIALOG_DATA) public data: Dog
) { }
ngOnInit() {
}
closeModal(): void {
this.dialogRef.close();
}
saveDog() {
if (this.data.id) {
this.dogsService.updateDog(this.data).subscribe(() => {
this.dialogRef.close();
})
}
else {
this.dogsService.addDog(this.data).subscribe(() => {
this.dialogRef.close();
})
}
}
}
Stilizam modala:
.container {
display: flex;
flex-direction: column;
}
.container > * {
width: 100%;
}