Chia sẻ dữ liệu giữa các component là một trong những khái niệm quan trọng khi bạn làm việc với Angular, bài viết dưới đây bao gồm một số phương thức phổ biến để truyền dữ liệu giữa các component với nhau.
Bài toán đặt ra yêu cầu như sau: Xây dựng chức năng hiển thị danh sách sản phẩm và đặt hàng có bố cục như hình vẽ bên dưới: Mô tả chức năng của các component ProductsComponent:
- Gọi API, lấy danh sách sản phẩm
- Hiển thị danh sách các ProductComponent
- Nhận sự kiện từ ProductComponent, cập nhật thông tin giỏ hàng
ProductComponent
- Hiển thị thông tin sản phẩm
- Gửi sự kiện khi người dùng cập nhật vào giỏ hàng
CartComponent
- Lấy dữ liệu của giỏ hàng từ service
- Hiển thị danh sách các CartItem
ProductDetailComponent
- Hiển thị thông tin chi tiết sản phẩm
- Cập nhật sản phẩm vào giỏ hàng, hiển thị số lượng nếu đã được chọn trước đó
Parent To Child: Sharing data via @Input
Đây là cách chia sẻ dữ liệu phổ biến và đơn giản nhất trong quá trình làm việc với Angular. Thông qua decorator @Input, Angular cho phép bạn truyền dữ liệu từ Component Cha sang Component Con.
products.component.ts
products.component.html
product.component.ts
Thông qua @Input, ngoài một đối tượng, Angular cho phép bạn truyền bất kỳ kiểu dữ liệu khả dụng trong JavaScript
Child To Parent: Sharing data via @Output and EventEmitter
Component Cha có thể nhận được dữ liệu từ Component Con bằng cách Component Con emit ra một sự kiện kèm theo đó là dữ liệu, Component Cha lắng nghe sự kiện và dữ liệu trả về. Angular cung cấp decorator @Output và EventEmitter
để giúp bạn làm được việc này.
product.component.ts
products.component.html
product.component.ts
Unrelated components: Sharing data via Service
Một nhược điểm khi sử dụng 2 cách trên là các component giao tiếp với nhau buộc phải có mối quan hệ Cha - Con. Ngoài ra, giả sử bạn có cây components như sau: Component A -> Component B -> Component C -> Component D
.
Bài toán đặt ra, A phải giao tiếp với C, bạn bắt buộc phải khai báo @Input, @Output cho cả B & C. Điều này khiến cho dữ liệu của bạn phải di chuyển rất phức tạp. Nhưng đừng lo, Angular cung cấp cho bạn một loạt các cách để bạn có thể truyền dữ liệu một cách đơn giản hơn trong trường hợp Component Tree của bạn trở nên phức tạp.
Ý tưởng: dữ liệu sẽ được lưu ở một nơi mà tất cả components đều có thể đến đó và có thể lấy được. Quay lại bài toán ban đầu, vì dữ liệu của giỏ hàng sẽ được truyền ở nhiều component với nhau, trong trường hợp này; ProductsComponent và CartComponent đều cần nên mình sẽ tạo ra CartService để lưu dữ liệu lên đấy.
Thuộc tính cart
chứa thông tin hiện tại của giỏ hàng.
Phương thức updateCart
thực hiện cập nhật thông tin giỏ hàng và thông báo sự thanh đổi đến các Consumer
cart.service.ts
cart.component.ts
product.component.ts
Unrelated components: Sharing data via Router
Trường hợp bạn muốn khi người dùng click vào sản phẩm, ửng dụng sẽ nhảy qua trang chi tiết sản phẩm và hiển thị thông tin tương ứng. Để biết được người dùng muốn xem thông tin của sản phẩm nào, bạn có thể lưu dữ liệu trên đường dẫn, ví dụ: http://localhost:4200/product/1 Dữ liệu bạn cần lưu ở đây là ProductId của sản phẩm
Bất kỳ component nào cũng có thể lấy được dữ liệu trên đường dẫn mà nó đang đứng Trước tiên, bạn cần định nghĩa dữ liệu được lưu ở phần Routing app.routes.ts
product-detail.component
Bạn hoàn toàn có thể lưu ProductId này lên trên Service vì ProductDetailComponent hoàn toàn có thể vào và có thể lấy được. Tuy nhiên, nếu người dùng load lại trang http://localhost:4200/product/1 thì giá trị không tồn tại vì chưa có lần cập nhật nào trước đó.
Unrelated components: Sharing data via Local Storage, Session Storage, Server
Vấn đề khi sử dụng Service để lưu trữ dữ liệu là khi người dùng reload lại trang, dữ liệu sẽ bị xóa hết. Hoặc khi sử dụng Router, rất khó để lưu kiểu dữ liệu phức tạp ví dụ như một mảng hoặc một đối tượng. Để giải quyết vấn đề này, chúng ta có thể lựa chọn một trong những nơi sau đây để lưu trữ: Local Storage, Session Storage hay thậm chí có thể lưu trữ trên Server.
Ở bài viết này, mình chỉ đề cập đến việc lưu trữ dữ liệu trên LocalStorage Danh sách các sản phẩm hiện tại mình đang lưu trên LocalStorage để ProductsComponent và ProductDetailComponent có thể lấy được.
products-detail.component.ts
product.component.ts
Chi tiết hơn mình sẽ chia sẻ ở bài sau nhé!!
Sharing data via @ViewChild/@ViewChildren
Ngoài ra còn một cách nữa để chia sẻ dữ liệu đối với component có mối quan hệ Cha - Con, vì trong phần demo, mình không trình bày nên sẽ để nội dung ở đây để bạn có thể tham khảo. @ViewChild/@ViewChildren cho phép Component Cha có thể intject dữ liệu vào Component Con Tuy nhiên, bạn chỉ làm được điều này sau khi Angular đã hoàn thành xong việc render template của component đó.
Có một chút thay đổi trong ParentComponent
products.components.ts
Tổng kết
Trên đây là một số cách phổ biến mình dùng trong dự án Angular, mỗi cách giải quyết cho một trường hợp cụ thể. Hy vọng bài viết này sẽ giúp ích cho bạn!!