Sau khi đã xây dựng giao diện của phần Categories, giờ là lúc chúng ta sẽ gọi các APIs của API Category Service để thực hiện các thao tác thêm, xoá, sửa, hiển thị tất cả các category rồi. Trong bài viết này, mình sẽ hướng dẫn bước đầu tiên là xây dựng phần hiển thị tất cả các category các bạn nhé!
Trước tiên, mình sẽ viết một class CategoryService để thực hiện việc gọi API lấy tất cả category của API Category Service.
Để làm được điều này, đầu tiên, mình sẽ tạo mới class CategoriesService nằm trong thư mục src/app/services như sau:
Class này sẽ được inject vào class CategoriesComponent để sử dụng nên mình sẽ khai báo nó cùng với decorator @Injectable như sau:
1 2 3 4 5 6 |
import { Injectable } from "@angular/core"; @Injectable() export class CategoriesService { } |
Tiếp theo mình sẽ tạo mới một đối tượng Category để chứa thông tin về category mà API Category Service sẽ trả về như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import { Injectable } from "@angular/core"; @Injectable() export class CategoriesService { } export class Category { id: string; name: string; code: string; description: string; } |
Để có thể gọi API lấy tất cả các category của API Category Service, mình sẽ khai báo sử dụng đối tượng HttpClient của Angular như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { Injectable } from "@angular/core"; @Injectable() export class CategoriesService { constructor(private http: HttpClient) { } } export class Category { id: string; name: string; code: string; description: string; } |
Bây giờ thì mình có thể viết phương thức để lấy tất cả các category từ API Category Service rồi:
1 2 3 |
findAllCategories(): Promise<Category[]> { return this.http.get<Category[]>("/category/all").toPromise(); } |
Như các bạn thấy, ở đây mình không khai báo baseUrl của API Category Service. Nguyên nhân là vì, cả API Category Service và phần Frontend này của ứng dụng Questions Management hiện tại mình sẽ chạy trên máy local của mình. Điều này sẽ gây ra lỗi bảo mật Cross-Origin Resource Sharing (CORS) nếu các bạn chạy ứng dụng của chúng ta bằng trình duyệt Chrome hay một số ứng dụng khác. Các bạn có thể tìm hiểu thêm về lỗi này trên internet nhé.
Để bỏ qua lỗi này, các bạn có thể giả lập để ứng dụng Frontend của chúng ta khi gọi đến các API của các service thông qua một proxy, bằng cách tạo mới một tập tin proxy.conf.json trong thư mục của Frontend project với nội dung như sau:
1 2 3 4 5 6 7 |
{ "/category/*": { "target": "http://localhost:8282", "secure": false, "logLevel": "debug" } } |
Với khai báo trên, các request ra ngoài với URL bắt đầu bằng “/category” sẽ được request tới địa chỉ http://localhost:8282, là địa chỉ của API Category Service đó các bạn. Trong tương lai, khi chúng ta deploy ứng dụng của chúng ta lên production thì chúng ta cần sửa lại phần này các bạn nhé!
Để sử dụng class CategoriesService này, chúng ta cần khai báo nó trong class AppModule, trong thuộc tính provider của decorator @NgModule. Ngoài ra chúng ta cũng cần khai báo import HttpClientModule nữa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { NavigationModule } from './navigation/navigation.module'; import { DashboardModule } from './dashboard/dashboard.module'; import { AppRoutingModule } from './app-routing.module'; import { QuestionsModule } from './questions/questions.module'; import { CategoriesService } from './services/categories.service'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule, AppRoutingModule, NavigationModule, DashboardModule, QuestionsModule ], providers: [ CategoriesService ], bootstrap: [ AppComponent ] }) export class AppModule { } |
OK, bây giờ chúng ta sẽ sử dụng class CategoriesService để lấy tất cả các category hiện có để display lên bảng trong giao diện của phần Categories.
Để làm được điều này, đầu tiên, chúng ta sẽ khai báo sử dụng class CategoriesService trong phần constructor của CategoriesComponent như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { Component, AfterViewInit } from "@angular/core"; import { CategoriesService } from "../../services/categories.service"; declare var $: any; @Component({ selector: 'qm-body', templateUrl: './categories.component.html' }) export class CategoriesComponent implements AfterViewInit { constructor(private categoriesService: CategoriesService) { } ngAfterViewInit(): void { $('#dataTables-categories').DataTable({ responsive: true }); } } |
sau đó, mình sẽ định nghĩa 1 biến categories để chứa tất cả các category sau khi lấy từ API Category Service về.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import { Component, AfterViewInit } from "@angular/core"; import { CategoriesService, Category } from "../../services/categories.service"; declare var $: any; @Component({ selector: 'qm-body', templateUrl: './categories.component.html' }) export class CategoriesComponent implements AfterViewInit { categories: Category[]; constructor(private categoriesService: CategoriesService) { } ngAfterViewInit(): void { $('#dataTables-categories').DataTable({ responsive: true }); } } |
Bây giờ thì chúng ta có thể viết code sử dụng phương thức findAllCategories() của CategoriesService để lấy tất cả category rồi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import { Component, AfterViewInit } from "@angular/core"; import { CategoriesService, Category } from "../../services/categories.service"; declare var $: any; @Component({ selector: 'qm-body', templateUrl: './categories.component.html' }) export class CategoriesComponent implements AfterViewInit { categories: Category[]; constructor(private categoriesService: CategoriesService) { } showAllCategories() { this.categoriesService.findAllCategories().then(r => { this.categories = r; setTimeout(function() { $('#dataTables-categories').DataTable({ responsive: true }); }, 100); }); } ngAfterViewInit(): void { this.showAllCategories(); } } |
Để hiển thị những category này lên, trong tập tin categories.component.html, phần table hiển thị danh sách category mình sẽ sửa lại như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-categories"> <thead> <tr> <th>Name</th> <th>Code</th> <th>Description</th> <th>Actions</th> </tr> </thead> <tbody> <tr *ngFor="let category of categories; let odd = odd; let even = even" [ngClass]="{ odd: odd, even: even }"> <td>{{ category.name }}</td> <td>{{ category.code }}</td> <td>{{ category.description }}</td> <td> <button type="button" class="btn btn-warning btn-circle"><i class="fa fa-edit"></i></button> <button type="button" class="btn btn-danger btn-circle"><i class="fa fa-trash"></i></button> </td> </tr> </tbody> </table> <!-- /.table-responsive --> |
Chúng ta cần phải khai báo CommonModule trong module QuestionsModule để sử dụng các Angular directive mà chúng ta đã sử dụng ở trên như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { NgModule } from "@angular/core"; import { CategoriesComponent } from "./categories/categories.component"; import { CommonModule } from "@angular/common"; @NgModule({ declarations: [ CategoriesComponent ], imports: [ CommonModule ], exports: [ CategoriesComponent ] }) export class QuestionsModule { } |
OK, mọi thứ đã xong, giờ chạy thử nha các bạn.
Ở đây, chúng ta cần chạy ứng dụng Angular với tập tin proxy.conf.json như sau:
1 |
ng serve --proxy-config proxy.conf.json |
Giả sử lúc này trong database mình đang có những category sau:
thì lúc này, nếu chạy ứng dụng các bạn sẽ thấy danh sách các category được hiển thị như sau: