[[oktatas:web:angular:angular httpclient|< Angular httpclient]] ====== Angular HttpClient - Dolgozók ====== * **Szerző:** Sallai András * Copyright (c) Sallai András, 2022, 2023 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu ===== Bevezetés ===== Ebben a leírásban dolgozók adatait fogjuk kezelni, a teljes **CRUD** műveleteket megvalósítva, **azonosítással**. A megvalósításhoz szükséges egy REST API kiszolgáló. ===== Backend oldal ===== Szükségünk van egy REST API szerverre, a következő végpontokkal. Ennek elkészítését lásd [[oktatas:web:back-end_framework:laravel:laravel_rest_api|Laravel API leírásban]] ^ Végpont ^ Metódus ^ Auth ^ CRUD ^ Leírás ^ | /employees | GET | nem | read | összes dolgozó | | /employees | POST | igen | create | új dolgozó | | /employees/{id} | GET | nem | read | egy dolgozó | | /employees/{id} | PUT | igen | update | dolgozó frissítése | | /employees/{id} | DELETE | igen | delete | dolgozó törlése | | /register | POST | nem | n/a | regisztráció | | /login | POST | nem | n/a | belépés | | /logout | POST | nem | n/a | kilépés | ==== GitHub-on ==== A backend elérhető a GitHubon a következő címen: * https://github.com/oktat/emp.git Beüzemelés a projekt docs könyvtárában. ===== REST API kliens ===== ==== Projekt készítése ==== Készítsünk egy angular projektet: ng new app01 Kérjünk router szolgáltatást. Lépjünk be, majd indítsunk kódszerkesztőt. cd app01 code . ===== Azonosítás ===== ==== Szükséges modul ==== import { HttpClientModule } from '@angular/common/http'; //... imports: [ HttpClientModule ], ==== Szolgáltatás létrehozása ==== Készítsünk egy szolgáltatást, auth néven: ng generate service shared/auth Létrejön két fájl: * src/app/shared/auth.service.ts * src/app/shared/auth.service.spec.ts Importáljuk a HttpClient és HttpHeaders osztályokat: import { HttpClient, HttpHeaders } from '@angular/common/http'; host = 'http://localhost:8000/api/'; A konstruktorba paraméterként vegyük fel a http objektumot: constructor(private http: HttpClient) { } A login() metódus: login(user: string, pass: string) { const authData = { name: user, password: pass } let httpHeaders = new HttpHeaders(); httpHeaders.set('Content-Type', 'application/json'); const httpOptions = { headers: httpHeaders } let endpoint = 'login'; let url = this.host + endpoint; return this.http.post(url, authData, httpOptions); } ==== Reaktív űrlap ==== import { ReactiveFormsModule } from '@angular/forms'; //... imports: [ ReactiveFormsModule ], //... ==== A login komponens ==== Készítsük el az employee komponenst: ng generate component login Elsőként importáljuk az AuthService osztályt: //... import { FormBuilder, FormGroup } from '@angular/forms'; import { AuthService } from '../shared/auth.service'; //... Injektáljuk és használjuk: //... export class LoginComponent implements OnInit { loginForm !: FormGroup; constructor( private auth: AuthService, private formBuilder: FormBuilder ) { } ngOnInit(): void { this.loginForm = this.formBuilder.group({ user: [''], pass: [''] }); } login() { let user = this.loginForm.value.user; let pass = this.loginForm.value.pass; this.auth.login(user, pass).subscribe({ next: data => { localStorage.setItem('userData', JSON.stringify(data)); }, error: err => { console.log('Hiba! A belépés sikertelen!') } }); } } A válasz részletezése: console.log(res.name); console.log(res.token);

Belépés

==== Az app.component ==== ==== Routing ==== import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { LoginComponent } from './login/login.component'; const routes: Routes = [ { path: 'login', component: LoginComponent} ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } ===== Kilépés ===== ==== Az auth bővítése ==== //... logout(name: string, token: string) { const userData = { name: name, tokenId: token } let httpHeaders = new HttpHeaders(); httpHeaders.set('Content-Type', 'application/json'); const httpOptions = { headers: httpHeaders } let endpoint = 'logout'; let url = this.host + endpoint; console.log(userData.name) return this.http.post(url, userData, httpOptions); } import { Component } from '@angular/core'; import { AuthService } from './shared/auth.service'; //... export class AppComponent { title = 'app01'; constructor(private auth: AuthService) {} logout() { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); console.log(userData.name); console.log(userData.token); this.auth.logout(userData.name, userData.token).subscribe({ next: res => { console.log(res) } }); } } ===== Összes dolgozó ===== ^ Végpont ^ Metódus ^ Azonosítás ^ CRUD ^ | /employees | GET | nem | Read | ==== Modul regisztrálása ==== Szükségünk van a HttpClientModule nevű modulra. Ha megcsináltuk az azonosítást, akkor ez kihagyható: import { HttpClientModule } from '@angular/common/http'; //... imports: [ HttpClientModule ], ==== Szolgáltatás létrehozása ==== Készítsünk egy szolgáltatást, api néven: ng generate service shared/api Létrejön két fájl: * src/app/shared/api.service.ts * src/app/shared/api.service.spec.ts Az api.service.ts fájlba írjuk a szolgáltatást. Az api.service.spec.ts a teszt az előbbi állomány számára. Vegyük az api.service.ts fájl, majd importáljuk a HttpClient: import { HttpClient } from '@angular/common/http'; A konstruktorba paraméterként vegyük fel a http objektumot: constructor(private http: HttpClient) { } Hozzuk létre a host adattagot és a getEmployees() metódust: //... host = 'http://localhost:8000/api/'; //... getEmployees() { let endpoint = 'employees'; let url = this.host + endpoint; return this.http.get(url); } ==== Employee komponense ==== ng generate component employee Szerkesszük az **src/app/employee/employee.component.ts** fájlt. * Importáljuk az **ApiService** osztályt. * Hozzunk létre egy **employees** adattagot. * Injektáljuk az **ApiService** osztályt. * Írjunk egy **getEmployees()** metódust. * Hívjuk meg a getEmployees() metódust a **ngOnInit()** metódusban. import { Component, OnInit } from '@angular/core'; import { ApiService } from '../shared/api.service'; @Component({ selector: 'app-employee', templateUrl: './employee.component.html', styleUrls: ['./employee.component.css'] }) export class EmployeeComponent implements OnInit { employees: any; constructor(private api: ApiService) { } ngOnInit(): void { this.getEmployees(); } getEmployees() { this.api.getEmployees().subscribe({ next: data => { this.employees = data; }, error: err => { console.log('Hiba! A dolgozók letöltése sikertelen!'); } }); } } ==== Sablonfájl ====

Dolgozók

Id Név Település Fizetés
{{ employee.id }} {{ employee.name }} {{ employee.city }} {{ employee.salary }}
==== Routing újra ==== const routes: Routes = [ { path: 'login', component: LoginComponent}, { path: 'employees', component: EmployeeComponent} ]; ===== Dolgozó hozzáadása ===== ==== Backend ==== Backend oldalon van egy /api/employees végpontunk, ahol POST metódussal új dolgozókat vehetünk fel. ^ Végpont ^ Metódus ^ Azonosítás ^ CRUD ^ | /employees | POST | igen | Create | ==== Szükséges modul ==== Ha még nincs regisztrálva az src/app/app.module.ts fájlban a HttpClientModule, akkor tegyük meg. import { HttpClientModule } from '@angular/common/http'; //... imports: [ HttpClientModule ], ==== Szolgáltatás létrehozása ==== Ha még nem létezik, hozzuk létre az api szolgáltatást: ng generate service shared/api Importáljuk a HttpClient és HttpHeaders osztályokat: import { HttpClient, HttpHeaders } from '@angular/common/http'; //... A konstruktorba paraméterként vegyük fel a http objektumot, ha még nincs felvéve: //... constructor(private http: HttpClient) { } //... Hozzuk létre a addEmployee() metódust: //... addEmployee(employee: any) { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); let httpHeaders = new HttpHeaders() .set('Authorization', `Bearer ${userData.token}`); const httpOptions = { headers: httpHeaders } let endpoint = 'employees'; let url = this.host + endpoint; return this.http.post(url, employee, httpOptions); } ==== Employee komponens hozzáadással ==== Reaktív űrlapot fogunk használni, ezért importáljuk a FormBuilder és a FormGroup osztályt, az **src/app/employee/employee.component.ts** fájlban: import { FormBuilder, FormGroup } from '@angular/forms'; Az EmployeeComponent osztályban vegyük fel a következő adattagokat, és injektáljuk FormBuilder osztályt: export class EmployeeComponent implements OnInit { employees: any; addForm !: FormGroup; addPanel: boolean = false; constructor( private api: ApiService, private formBuilder: FormBuilder ) { } //... Az ngOnInit() függvényben készítsük elő az űrlapot: ngOnInit(): void { this.getEmployees(); this.addForm = this.formBuilder.group({ name: [''], city: [''], salary: [''] }); } Írjunk itt is egy addEmployee() metódust, ami az api szolgáltatás addEmployee() metóudásával dolgozik. addEmployee() { let employee = { name: this.addForm.value.name, city: this.addForm.value.city, salary: this.addForm.value.salary, } this.api.addEmployee(employee).subscribe({ next: res => { console.log(res) this.employees.push(res); } }); } A hozzáadó űrlap megjelenítéséhez, rejtéséhez készítsünk egy showAddPanel() metódust: showAddPanel() { this.addPanel = true; } ==== Az employee komponens sablonja ==== Adjuk meg a fájl elején egy gombot, a végéhez pedig fűzzünk egy űrlapot:
A "Hozzáad" gomb a táblázat előtt, az űrlap a táblázat után. ===== Dolgozók törlése ===== ^ Végpont ^ Metódus ^ Azonosítás ^ CRUD ^ | /employees/{id} | DELETE | igen | Delete | ==== api.service ==== Az api szolgáltatás bővítése delEmployee() metódussal, a **src/app/shared/api.service.ts** fájlban: //... delEmployee(id: number) { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); let httpHeaders = new HttpHeaders() .set('Authorization', `Bearer ${userData.token}`); const httpOptions = { headers: httpHeaders } let endpoint = 'employees'; let url = this.host + endpoint + '/' + id; return this.http.delete(url, httpOptions); } ==== Az employees komponens ==== Az employee komponensben is megírjuk a delEmployee() metódust: //... delEmployee(employee: any) { this.api.delEmployee(employee.id).subscribe({ next: res => { console.log(res); this.employees.forEach( (emp: any, index: number) => { if (emp.id === employee.id ) { this.employees.splice(index, 1) } }) } }); } ==== Employee komponens sablonja ==== Fel kell vennünk egy új táblázatelemet a **src/app/employee/employee.component.html** fájlban: A teljes táblázat így néz ki:
Id Név Település Fizetés
{{ employee.id }} {{ employee.name }} {{ employee.city }} {{ employee.salary }}
===== Dolgozók szerkesztése ===== ^ Végpont ^ Metódus ^ Azonosítás ^ CRUD ^ | /employees/{id} | PUT | igen | Update | ==== ApiService ==== Szükség van egy updateEmployee() metódusra: //... updateEmployee(employee: any) { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); let httpHeaders = new HttpHeaders() .set('Authorization', `Bearer ${userData.token}`); const httpOptions = { headers: httpHeaders } let endpoint = 'employees'; let url = this.host + endpoint + '/' + employee.id; return this.http.put(url, employee, httpOptions); } ==== EmployeeComponent ==== Szükség van két új adattagra az EmployeeComponent osztályban: editPanel: boolean = false; editForm !: FormGroup; Az ngOnInit() metódusban inicializálni kell az editForm objektumot: //... this.editForm = this.formBuilder.group({ id: [''], name: [''], city: [''], salary: [''] }); Kell egy metódus, ami megjeleníti a szerkesztő felületet: showEdit(employee: any) { this.editForm.patchValue({id: employee.id}); this.editForm.patchValue({name: employee.name}); this.editForm.patchValue({city: employee.city}); this.editForm.patchValue({salary: employee.salary}); this.editPanel = true; } Kell egy metódus amit frissíti az adatokat: updateEmployee() { let employee = { id: this.editForm.value.id, name: this.editForm.value.name, city: this.editForm.value.city, salary: this.editForm.value.salary } this.api.updateEmployee(employee).subscribe({ next: res => { console.log(res); this.editPanel = false; this.getEmployees(); } }); } ==== Az employee sablon ==== Fűzzük az employee.component.html végéhez: //...
==== Teljes kód ==== import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { LoginComponent } from './login/login.component'; import { ReactiveFormsModule } from '@angular/forms'; import { EmployeeComponent } from './employee/employee.component'; @NgModule({ declarations: [ AppComponent, LoginComponent, EmployeeComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } import { Component } from '@angular/core'; import { AuthService } from './shared/auth.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app01'; constructor(private auth: AuthService) {} logout() { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); console.log(userData.name); console.log(userData.token); this.auth.logout(userData.name, userData.token).subscribe({ next: res => { console.log(res) } }); } } import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { EmployeeComponent } from './employee/employee.component'; import { LoginComponent } from './login/login.component'; const routes: Routes = [ { path: 'login', component: LoginComponent}, { path: 'employees', component: EmployeeComponent} ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AuthService { host = 'http://localhost:8000/api/'; constructor(private http: HttpClient) { } login(user: string, pass: string) { const authData = { name: user, password: pass } let httpHeaders = new HttpHeaders(); httpHeaders.set('Content-Type', 'application/json'); const httpOptions = { headers: httpHeaders } let endpoint = 'login'; let url = this.host + endpoint; return this.http.post(url, authData, httpOptions); } logout(name: string, token: string) { const userData = { name: name, tokenId: token } let httpHeaders = new HttpHeaders(); httpHeaders.set('Content-Type', 'application/json'); const httpOptions = { headers: httpHeaders } let endpoint = 'logout'; let url = this.host + endpoint; console.log(userData.name) return this.http.post(url, userData, httpOptions); } } import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class ApiService { host = 'http://localhost:8000/api/'; constructor(private http: HttpClient) { } getEmployees() { let endpoint = 'employees'; let url = this.host + endpoint; return this.http.get(url); } addEmployee(employee: any) { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); let httpHeaders = new HttpHeaders() .set('Authorization', `Bearer ${userData.token}`); const httpOptions = { headers: httpHeaders } let endpoint = 'employees'; let url = this.host + endpoint; return this.http.post(url, employee, httpOptions); } delEmployee(id: number) { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); let httpHeaders = new HttpHeaders() .set('Authorization', `Bearer ${userData.token}`); const httpOptions = { headers: httpHeaders } let endpoint = 'employees'; let url = this.host + endpoint + '/' + id; return this.http.delete(url, httpOptions); } updateEmployee(employee: any) { let jsonUserData: any = localStorage.getItem('userData'); let userData = JSON.parse(jsonUserData); let httpHeaders = new HttpHeaders() .set('Authorization', `Bearer ${userData.token}`); const httpOptions = { headers: httpHeaders } let endpoint = 'employees'; let url = this.host + endpoint + '/' + employee.id; return this.http.put(url, employee, httpOptions); } } import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { AuthService } from '../shared/auth.service'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { loginForm !: FormGroup; constructor( private auth: AuthService, private formBuilder: FormBuilder ) { } ngOnInit(): void { this.loginForm = this.formBuilder.group({ user: [''], pass: [''] }); } login() { let user = this.loginForm.value.user; let pass = this.loginForm.value.pass; this.auth.login(user, pass).subscribe({ next: data => { localStorage.setItem('userData', JSON.stringify(data)); }, error: err => { console.log('Hiba! A belépés sikertelen!') } }); } }

Belépés

import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { ApiService } from '../shared/api.service'; @Component({ selector: 'app-employee', templateUrl: './employee.component.html', styleUrls: ['./employee.component.css'] }) export class EmployeeComponent implements OnInit { addPanel: boolean = false; editPanel: boolean = false; employees: any; addForm !: FormGroup; editForm !: FormGroup; constructor( private api: ApiService, private formBuilder: FormBuilder ) { } ngOnInit(): void { this.getEmployees(); this.addForm = this.formBuilder.group({ name: [''], city: [''], salary: [''] }); this.editForm = this.formBuilder.group({ id: [''], name: [''], city: [''], salary: [''] }); } getEmployees() { this.api.getEmployees().subscribe({ next: data => { this.employees = data; }, error: err => { console.log('Hiba! A dolgozók letöltése sikertelen!'); } }); } addEmployee() { let employee = { name: this.addForm.value.name, city: this.addForm.value.city, salary: this.addForm.value.salary, } this.api.addEmployee(employee).subscribe({ next: res => { console.log(res) this.employees.push(res); } }); } showAddPanel() { this.addPanel = true; } delEmployee(employee: any) { this.api.delEmployee(employee.id).subscribe({ next: res => { console.log(res); this.employees.forEach( (emp: any, index: number) => { if (emp.id === employee.id ) { this.employees.splice(index, 1) } }) } }); } showEdit(employee: any) { this.editForm.patchValue({id: employee.id}); this.editForm.patchValue({name: employee.name}); this.editForm.patchValue({city: employee.city}); this.editForm.patchValue({salary: employee.salary}); this.editPanel = true; } updateEmployee() { let employee = { id: this.editForm.value.id, name: this.editForm.value.name, city: this.editForm.value.city, salary: this.editForm.value.salary } this.api.updateEmployee(employee).subscribe({ next: res => { console.log(res); this.editPanel = false; this.getEmployees(); } }); } }

Dolgozók

Id Név Település Fizetés
{{ employee.id }} {{ employee.name }} {{ employee.city }} {{ employee.salary }}
===== Függelék ===== ==== HttpHeaders változatok ==== A httpHeaders objektum így is létrehozható: const httpHeaders = new HttpHeaders() .set('Content-Type', 'application/json'); const httpHeaders = new HttpHeaders({ 'Content-Type': 'application/json' }); ==== Lekérés azonosítással ==== Ha védett lenne a dolgozók lekérése, akkor a tokent is el kellene küldenünk a lekéréskor: Hozzuk létre a getEmployees() metódust: getEmployees() { let url = 'http://localhost:8000/api/employees'; let token = '3|7eBr5iAUPgqQz3lxIFgC72Yh3ERO76g1MyuHNOGD'; let header = { headers: new HttpHeaders() .set('Authorization', `Bearer ${token}`) } return this.http.get(url, header); }