Quản lý dữ liệu trong ứng dụng Angular

Hướng dẫn này được xây dựng dựa trên bước thứ hai của hướng dẫn Bắt đầu với ứng dụng Angular cơ bản đó là Thêm điều hướng vào ứng dụng Angular.

Ở giai đoạn phát triển này, ứng dụng cửa hàng có danh mục sản phẩm với hai view là: danh sách sản phẩm và chi tiết sản phẩm.

Người dùng có thể nhấp vào tên sản phẩm từ danh sách để xem thông tin chi tiết sản phẩm trong view mới, với một URL hoặc tuyến đường riêng biệt.

Bước này của hướng dẫn sẽ hướng dẫn bạn cách tạo giỏ hàng theo các giai đoạn sau:

  • Cập nhật view chi tiết sản phẩm để thêm nút Buy, nút này sẽ thêm sản phẩm hiện tại vào danh sách sản phẩm mà dịch vụ giỏ hàng quản lý.
  • Thêm component giỏ hàng, hiển thị các mặt hàng trong giỏ hàng.
  • Thêm component vận chuyển, component này truy xuất giá vận chuyển cho các mặt hàng trong giỏ hàng bằng cách sử dụng HttpClient của Angular để truy xuất dữ liệu vận chuyển từ tệp .json.

Dịch vụ giỏ hàng

Trong Angular, một dịch vụ là một instance của một lớp mà bạn có thể cung cấp cho bất kỳ phần nào trong ứng dụng của mình bằng cách sử dụng dependency injection của Angular.

Hiện tại, người dùng có thể xem thông tin sản phẩm, đồng thời ứng dụng có thể giả lập chia sẻ và thông báo về các thay đổi của sản phẩm.

Bước tiếp theo là xây dựng cách để người dùng thêm sản phẩm vào giỏ hàng. Phần này hướng dẫn bạn thêm nút Buy và thiết lập dịch vụ giỏ hàng để lưu trữ thông tin về các sản phẩm trong giỏ hàng.

Tạo dịch vụ giỏ hàng

1. Để tạo dịch vụ giỏ hàng, nhấp chuột phải vào thư mục app, chọn Angular Generator và chọn Service. Đặt tên cho dịch vụ mới là cart.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CartService {

  constructor() {}

}
src/app/cart.service.ts

2. Import interface Product từ ./products.js.

3. Trong lớp CartService, định nghĩa thuộc tính items để lưu trữ mảng các sản phẩm hiện tại trong giỏ hàng.

import { Product } from './products';
/* . . . */
export class CartService {
  items: Product[] = [];
/* . . . */
}
src/app/cart.service.ts

4. Định nghĩa các phương thức để thêm các mặt hàng vào giỏ hàng, trả lại các mặt hàng trong giỏ hàng và xóa các mặt hàng trong giỏ hàng.

export class CartService {
  items: Product[] = [];
/* . . . */

  addToCart(product: Product) {
    this.items.push(product);
  }

  getItems() {
    return this.items;
  }

  clearCart() {
    this.items = [];
    return this.items;
  }
/* . . . */
}
src/app/cart.service.ts
  • Phương thức addToCart() sẽ thêm một sản phẩm vào giỏ hàng.
  • Phương thức getItems() sẽ trả về tất cả mặt hàng có trong giỏ hàng.
  • Phương thức clearCart() sẽ xóa tất cả mặt hàng trong giỏ hàng.

Sử dụng dịch vụ giỏ hàng

Phần này sẽ hướng dẫn bạn cách sử dụng CartService để thêm sản phẩm vào giỏ hàng.

1. Import các thành phần sau vào trong file product-details.component.ts.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Product, products } from '../products';
import { CartService } from '../cart.service';
src/app/product-details/product-details.component.ts

2. Inject dịch vụ giỏ hàng bằng cách thêm nó vào phương thức constructor().

export class ProductDetailsComponent implements OnInit {
  constructor(
    private route: ActivatedRoute,
    private cartService: CartService
  ) { }
}
src/app/product-details/product-details.component.ts

3. Định nghĩa phương thức addToCart() để thêm sản phẩm hiện tại vào giỏ hàng.

export class ProductDetailsComponent implements OnInit {
  addToCart(product: Product) {
    this.cartService.addToCart(product);
    window.alert('Your product has been added to the cart!');
  }
}
src/app/product-details/product-details.component.ts

Phương thức addToCart() sẽ làm những việc sau đây:

  • Nhận product hiện tại làm tham số đầu vào.
  • Sử dụng phương thức addToCart() của CartService để thêm sản phẩm vào giỏ hàng.
  • Hiển thị thông báo bạn đã thêm sản phẩm vào giỏ hàng.

4. Trong file template product-details.component.html, thêm nút Buy và liên kết sự kiện click() với phương thức addToCart(). Mã này thêm nút Buy vào template chi tiết sản phẩm để thêm sản phẩm hiện tại vào giỏ hàng.

<h2>Product Details</h2>

<div *ngIf="product">
  <h3>{{ product.name }}</h3>
  <h4>{{ product.price | currency }}</h4>
  <p>{{ product.description }}</p>

  <button (click)="addToCart(product)">Buy</button>
</div>
src/app/product-details/product-details.component.html

5. Kiểm tra nút Buy bằng cách làm mới ứng dụng và nhấp vào tên sản phẩm để hiển thị thông tin chi tiết sản phẩm.

Thêm nút Buy vào trang thông tin chi tiết sản phẩm

6. Nhấn nút Buy để thêm sản phẩm vào giỏ hàng và hiển thị thông báo xác nhận.

Hiển thị thông báo khi mua hàng

Tạo view giỏ hàng

Để khách hàng xem giỏ hàng của họ, bạn có thể tạo view giỏ hàng theo hai bước:

  1. Tạo component giỏ hàng và cấu hình định tuyến đến component mới.
  2. Hiển thị các mặt hàng trong giỏ hàng.

Tạo component giỏ hàng

Để tạo view giỏ hàng, hãy làm theo các bước tương tự bạn đã làm để tạo ProductDetailsComponent và cấu hình định tuyến cho component mới.

1. Tạo component giỏ hàng được đặt tên cart bằng cách nhấp chuột phải vào thư mục app, chọn Angular GeneratorComponent.

import { Component } from '@angular/core';

@Component({
  selector: 'app-cart',
  templateUrl: './cart.component.html',
  styleUrls: ['./cart.component.css']
})
export class CartComponent {

  constructor() { }

}
src/app/cart/cart.component.ts

StackBlitz cũng tạo ngOnInit() theo mặc định trong các component. Bạn có thể bỏ qua ngOnInit() của CartComponent trong hướng dẫn này.

2. Mở file app.module.ts và thêm một tuyến đường cho component CartComponent, với pathcart và component là CartComponent.

@NgModule({
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
      { path: 'products/:productId', component: ProductDetailsComponent },
      { path: 'cart', component: CartComponent },
    ])
  ],
src/app/app.module.ts

3. Cập nhật nút Checkout để nó định tuyến đến URL /cart. Trong top-bar.component.html, thêm directive routerLink trỏ đến /cart.

<a routerLink="/cart" class="button fancy-button">
  <i class="material-icons">shopping_cart</i>Checkout
</a>
src/app/top-bar/top-bar.component.html

4. Kiểm tra CartComponent bằng cách nhấp vào nút Checkout. Bạn có thể thấy "cart works!" và URL có dạng https://getting-started.stackblitz.io/cart. Domain getting-started.stackblitz.io có thể khác đối với dự án StackBlitz của bạn.

Truy cập giỏ hàng

Hiển thị các mặt hàng trong giỏ hàng

Phần này hướng dẫn bạn cách sử dụng dịch vụ giỏ hàng để hiển thị các sản phẩm trong giỏ hàng.

1. Import các thành phần sau trong file cart.component.ts.

import { Component } from '@angular/core';
import { CartService } from '../cart.service';
src/app/cart/cart.component.ts

2. Inject CartService để CartComponent có thể sử dụng nó bằng cách thêm nó vào phương thức constructor().

export class CartComponent {

  constructor(
    private cartService: CartService
  ) { }
}
src/app/cart/cart.component.ts

3. Định nghĩa thuộc tính items để lưu trữ các sản phẩm trong giỏ hàng.

export class CartComponent {
  items = this.cartService.getItems();

  constructor(
    private cartService: CartService
  ) { }
}
src/app/cart/cart.component.ts

Mã này gán giá trị cho thuộc tính items bằng cách sử dụng phương thức getItems() của CartService. Bạn đã định nghĩa phương thức này khi bạn tạo cart.service.ts.

4. Cập nhật template của giỏ hàng với tiêu đề và sử dụng thẻ <div> với directive *ngFor để hiển thị từng phần tử trong giỏ hàng với tên và giá của nó. Template của CartComponent trông sẽ như sau.

<h3>Cart</h3>

<div class="cart-item" *ngFor="let item of items">
  <span>{{ item.name }}</span>
  <span>{{ item.price | currency }}</span>
</div>
src/app/cart/cart.component.html

5. Kiểm tra giỏ hàng của bạn hoạt động như mong đợi:

  • Nhấp vào My Store
  • Nhấp vào tên sản phẩm để hiển thị thông tin chi tiết.
  • Bấm Buy để thêm sản phẩm vào giỏ hàng.
  • Nhấp vào Checkout để xem giỏ hàng.
Xem giỏ hàng

Để biết thêm thông tin về các dịch vụ, hãy xem Giới thiệu về Dịch vụ và Dependency Injection.

Truy xuất phí vận chuyển

Máy chủ thường trả về dữ liệu dưới dạng stream. Stream rất hữu ích vì chúng giúp bạn dễ dàng chuyển đổi dữ liệu trả về và thực hiện sửa đổi theo cách bạn yêu cầu dữ liệu đó. Angular HttpClient là một cách tích hợp để tìm nạp dữ liệu từ các API bên ngoài và cung cấp chúng cho ứng dụng của bạn dưới dạng stream.

Phần này hướng dẫn bạn cách sử dụng HttpClient để lấy phí vận chuyển từ tệp bên ngoài.

Ứng dụng mà StackBlitz tạo cho hướng dẫn này đi kèm với dữ liệu vận chuyển được định nghĩa trước trong file assets/shipping.json. Sử dụng dữ liệu này để tính phí vận chuyển cho các mặt hàng trong giỏ hàng.

[
  {
    "type": "Overnight",
    "price": 25.99
  },
  {
    "type": "2-Day",
    "price": 9.99
  },
  {
    "type": "Postal",
    "price": 2.99
  }
]
src/assets/shipping.json

Cấu hình AppModule để sử dụng HttpClient

Để sử dụng Angular HttpClient, bạn phải cấu hình ứng dụng của mình để sử dụng HttpClientModule.

HttpClientModule của Angular đăng ký các nhà cung cấp mà ứng dụng của bạn cần để sử dụng dịch vụ HttpClient trong suốt ứng dụng của bạn.

1. Trong file app.module.ts, import HttpClientModule từ gói @angular/common/http ở đầu tệp cùng với các import khác. Vì có một số import khác, đoạn mã này bỏ qua chúng cho ngắn gọn. Đảm bảo giữ nguyên các import hiện có.

import { HttpClientModule } from '@angular/common/http';
src/app/app.module.ts

Để đăng ký các nhà cung cấp HttpClient của Angular trên toàn cầu, hãy thêm HttpClientModule vào mảng AppModule @NgModule() imports.

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
      { path: 'products/:productId', component: ProductDetailsComponent },
      { path: 'cart', component: CartComponent },
    ])
  ],
  declarations: [
    AppComponent,
    TopBarComponent,
    ProductListComponent,
    ProductAlertsComponent,
    ProductDetailsComponent,
    CartComponent,
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }
src/app/app.module.ts

Cấu hình CartService để sử dụng HttpClient

Bước tiếp theo là đưa dịch vụ HttpClient vào dịch vụ của bạn để ứng dụng của bạn có thể tìm nạp dữ liệu và tương tác với các tài nguyên và API bên ngoài.

1. Trong filecart.service.ts, import HttpClient từ gói @angular/common/http.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Product } from './products';
src/app/cart.service.ts

2. Inject HttpClient vào phương thức constructor() của CartService.

export class CartService {
  items: Product[] = [];

  constructor(
    private http: HttpClient
  ) {}
/* . . . */
}
src/app/cart.service.ts

Cấu hình CartService để nhận phí vận chuyển

Để nhận dữ liệu vận chuyển từ file shipping.json, Bạn có thể sử dụng phương thức get() của HttpClient.

1. Trong file cart.service.ts, bên dưới phương thức clearCart(), hãy định nghĩa phương thức getShippingPrices() mới sử dụng phương thức get() của HttpClient.

export class CartService {
/* . . . */
  getShippingPrices() {
    return this.http.get<{type: string, price: number}[]>('/assets/shipping.json');
  }
}
src/app/cart.service.ts

Để biết thêm thông tin về Angular HttpClient, hãy xem hướng dẫn Tương tác Client-Server.

Tạo component vận chuyển

Bây giờ bạn đã cấu hình ứng dụng của mình để truy xuất dữ liệu vận chuyển, bạn có thể tạo một nơi để hiển thị dữ liệu đó.

1. Tạo một component mới được đặt tên là shipping bằng cách nhấp chuột phải vào thư mục app, chọn Angular Generator và chọn Component.

import { Component } from '@angular/core';

@Component({
  selector: 'app-shipping',
  templateUrl: './shipping.component.html',
  styleUrls: ['./shipping.component.css']
})
export class ShippingComponent {

  constructor() { }

}
src/app/shipping/shipping.component.ts

2. Trong file app.module.ts, thêm một tuyến đường cho phí vận chuyển. Thêm pathshipping và một componentShippingComponent.

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
      { path: 'products/:productId', component: ProductDetailsComponent },
      { path: 'cart', component: CartComponent },
      { path: 'shipping', component: ShippingComponent },
    ])
  ],
  declarations: [
    AppComponent,
    TopBarComponent,
    ProductListComponent,
    ProductAlertsComponent,
    ProductDetailsComponent,
    CartComponent,
    ShippingComponent
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }
src/app/app.module.ts

Chưa có liên kết đến component vận chuyển mới, nhưng bạn có thể xem template của nó trong ô xem trước bằng cách nhập URL mà tuyến đường của nó chỉ định. URL có dạng: https://getting-started.stackblitz.io/shipping trong đó domain getting-started.stackblitz.io có thể khác đối với dự án StackBlitz của bạn.

Cấu hình ShippingComponent để sử dụng CartService

Phần này hướng dẫn bạn cách sửa đổi ShippingComponent để truy xuất dữ liệu vận chuyển qua HTTP từ tệp shipping.json.

1. Trong tệp shipping.component.ts, import CartService như sau.

import { Component } from '@angular/core';

import { CartService } from '../cart.service';
src/app/shipping/shipping.component.ts

2. Chèn dịch vụ giỏ hàng trong phương thức constructor() của ShippingComponent.

constructor(private cartService: CartService) {
}
src/app/shipping/shipping.component.ts

3. Định nghĩa thuộc tính shippingCosts, gán giá trị cho thuộc tính shippingCosts bằng cách sử dụng phương thức getShippingPrices() từ CartService.

export class ShippingComponent {
  shippingCosts = this.cartService.getShippingPrices();
}
src/app/shipping/shipping.component.ts

4. Cập nhật template của ShippingComponent để hiển thị danh sách phí vận chuyển bằng cách sử dụng đường ống async.

<h3>Shipping Prices</h3>

<div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
  <span>{{ shipping.type }}</span>
  <span>{{ shipping.price | currency }}</span>
</div>
src/app/shipping/shipping.component.html

Đường ống async trả về giá trị mới nhất từ ​​một luồng dữ liệu và tiếp tục làm như vậy cho vòng đời của một component nhất định. Khi Angular hủy component đó, đường ống async sẽ tự động dừng lại. Để biết thông tin chi tiết về đường ống async, hãy xem tài liệu API AsyncPipe.

5. Thêm một liên kết từ màn hình CartComponent đến màn hình ShippingComponent.

<h3>Cart</h3>

<p>
  <a routerLink="/shipping">Shipping Prices</a>
</p>

<div class="cart-item" *ngFor="let item of items">
  <span>{{ item.name }}</span>
  <span>{{ item.price | currency }}</span>
</div>
src/app/cart/cart.component.html

6. Nhấp vào nút Checkout để xem giỏ hàng đã được cập nhật. Hãy nhớ rằng việc thay đổi ứng dụng sẽ làm mới bản xem trước, làm trống giỏ hàng.

Màn hình giỏ hàng

Nhấp vào liên kết để điều hướng đến trang bảng giá vận chuyển.

Màn hình bảng giá vận chuyển

Tiếp theo là gì

Bây giờ bạn có một ứng dụng cửa hàng với danh mục sản phẩm, giỏ hàng và bạn có thể tra cứu phí vận chuyển.

Để tiếp tục khám phá Angular:

AngularTypeScript
Bài Viết Liên Quan:
Trình khởi động bootstrap trong Angular
Trung Nguyen 26/07/2021
Trình khởi động bootstrap trong Angular

Trong hướng dẫn này, chúng ta sẽ tìm hiểu về trình khởi động bootstrap và cách Angular hoạt động bên trong và khởi động ứng dụng của chúng ta.

Cách tạo một dự án mới trong Angular
Trung Nguyen 25/07/2021
Cách tạo một dự án mới trong Angular

Trong hướng dẫn này, chúng tôi sẽ chỉ cho bạn cách sử dụng Angular CLI để tạo một dự án mới trong Angular.

Không gian làm việc và Cấu trúc file dự án
Trung Nguyen 22/07/2021
Không gian làm việc và Cấu trúc file dự án

Trong hướng dẫn này, bạn sẽ tìm hiểu về không dan làm việc và cấu trúc file dự án ứng dụng, dự án thư viện của Angular.

Service và Dependency Injection trong Angular
Trung Nguyen 21/07/2021
Service và Dependency Injection trong Angular

Trong bài viết này, bạn sẽ tìm hiểu vì sao Angular lại tách riêng component và service, cách sử dụng dependency injection để khởi tạo instance của service.