Angular trong phát triển ứng dụng web, part 2
Tiếp tục series Angular trong phát triển ứng dụng web, ở phần 2 này chúng ta sẽ đi vào mô hình làm việc và tính năng của Angular.
Nhưng trước tiên mình sẽ điểm lại những tính năng chính của framework:
- Template: Cho phép người dùng xây dựng các component (thành phần) riêng có thể đóng gói và tái sử dụng cao.
- Data-Binding: Tính năng tự động đồng bộ hóa dữ liệu giữa hai chiều model và view khi view có sự thay đổi nào đó.
- Service: Có thể là một value, phương thức hoặc tính năng nào đó mà ứng dụng cần.
- Dependency injection: Cho phép người dùng có thể nhúng service hoặc đoạn code và đưa chúng vào bất kỳ nơi nào cần.
Đầu tiên mình sẽ đi vào cấu trúc của một dự án Angular
Folder cha (root) gồm có các folder con là e2e, node_module và src. Ngoài ra có thêm một số file cấu hình bên ngoài.
- Folder e2e: Chứa các file liên quan đến việc testing. Angular sử dụng thư viện protractor để thực hiện automation test trên các trình duyệt.
- Folder node_modules: Nơi chứa các thư viện và được download về cho dự án angular. Nó được quản lý bằng NPM có nghĩa là ta dùng NPM để xoá, thêm các thư viện.
- Folder src: Nơi chứa các source khi chương trình chạy. Đây là nơi tập trung các dòng code của ứng dụng angular.
- Folder app: Angular cli tạo ra folder này giống như folder cha của ứng dụng, Angular cli tạo ra như một ví dụ mẫu để sau này ta tạo các component khác. Trong folder app thường có:
- app-routing.module.ts: file này dùng để điều hướng.
- component.css: chúng ta định nghĩa các css mà component sẽ dùng.
- component.html: nơi chúng ta viết các files html. Là tầng view mà người dùng có thể thấy được.
- component.spec.ts: file này dùng cho việc testing (kiểm thử).
- component.ts (component class): là file xử lý các nghiệp vụ nó giống như Controller bên Spring Web.
- module.ts: file dùng để cấu hình cho module app.
- .editorconfig: File này dùng để cấu hình nếu trình soạn thảo code chúng ta dùng là Visual Studio. Mình có thể thay đổi cấu hình tại đây.
- .gitignore: Dùng để mô tả file nào được đưa lên github file nào không được đưa lên.
- json: Dùng để cấu hình lại Angular Cli.
- browserslist: Những phiên bản browser sẽ tương thích với dự án angular.
- config.js: File này dùng để chạy các testing (kiểm thử) các chức năng.
- json: File này chứa các thư viện cần thiết cho dự án angular, ngoài ra nếu ta thêm một thư viện bên thứ 3 vào thì khai báo trong này.
- js: Dùng để kiểm tra code có chất lượng hay không, có dễ đọc hay dễ bảo trì không, có theo chuẩn không.
Cơ chế hoạt động của Angular
Để Angular render giao diện và hiển thị lên trình duyệt chúng ta chạy command “ ng serve -o “ (trong đó -o là option mở giao diện web dev trên cửa số trình duyệt mới).
Ta có thể hiểu cơ chế hoạt động của Angular như sau:
- Angular sẽ load file index.html.
- Angular tiếp tục nạp các thư viện và các thư viện bên thứ 3 vào.
- Tiếp đó Angular sẽ load file main.ts.
- Trong file main.ts Angular sẽ load module cha là app.modules.ts.
- modules.ts load lên module cha component (root) hay còn gọi là root component. Trong dự án Angular ta sẽ có nhiều component. Mỗi component là 1 phần của view hiển thị cho người dùng.
- Trong module component sẽ có các file html, css (view) lúc đó sẽ hiển thị trang web cho người dùng.
Trang đầu tiên mà Angular gọi là…
File index.html là file đầu tiên mà Angular sẽ gọi khi ứng dụng được triển khai. Nội dung file index.html có dạng.
Như ta thấy không có file javascript và css có trong index.html. Trong thẻ body chỉ chứa 1 thẻ duy nhất là app-root.
Khi chúng ta thực hiện ng build, Angular sẽ biên dịch các file .ts các thư viện bên thứ 3 và nhúng vào index như sau.
Ta có thể tìm thấy file này trong folder dist. Khi chạy lệnh ng build thì Angular sẽ tạo cho chúng ta 1 folder là dist nó nén hết tất cả file dự án lại.
Như vậy ta thấy angular thêm vào 3 files javascript vào trong file index.html những file này có tác dụng như sau:
- 22eb52b7ae39d210.js: sử dụng Webpack để triển khai chạy ứng dụng angular.
- 1abcbd05316f6609.js: hỗ trợ chạy trên nhiều trình duyệt.
- 1a28e5c215027b7d.js: các code của ứng dụng mình.
main.ts
File main.ts có nội dung như bên dưới đây.
- Chúng ta thấy import platformBrowserDynamic để nói với Angular là sẽ load ứng dụng Angular bằng trình duyệt trên desktop.
- Tiếp đến chúng ta thấy Angular import AppModule. AppModule là component cha của cả ứng dụng Angular. Angular tổ chức code theo modules phân tầng. Module cha có nhiều module con, module con có nhiều module con trong đó nữa. Như vậy AppModule là module cha của ứng dụng Angular. Tất cả các ứng dụng Angular phải có ít nhất 1 module cha để load lên đầu tiên ta gọi nó là root module. Sau đó đến các module thành phần bên trong.
Root Module
Đầu tiên Angular sẽ load file AppModule. File AppModule được mô tả sau đây.
Sau khi root module được gọi lên thì nó cần tối thiểu 1 component được load lên. Trong ví dụ này ta sẽ load component đầu tiền là AppComponent. Trong dự án Angular ta sẽ có 1 component cha, trong component cha sẽ có nhiều component con. Dưới đây là khai báo AppComponent được load lên.
@NgModule trong Angular dùng để khai báo các modules con và các thirdparties sẽ được dùng trong ứng dụng.
- imports : Dùng để nhúng các modules bên ngoài và các thirdparties sẽ được dùng chung với ứng dụng Angular.
- declarations : Nơi sẽ khai báo các components cha, con các directive hoặc service mà ta sử dụng trong dự án Angular.
- bootstrap : Chỉ ra component nào Angular sẽ load lên khi Angular Module được load.
Component
Trong @NgModule ta có bootstrap : [AppComponent] nói cho Angular biết là phải load AppComponent lên. Code Component được hiển thị như sau:
- Cấu tạo 1 component gồm 3 files. 1 là file Class Component, 2 là file html hiển thị view, 3 là file css.
- Class Component được đánh dấu với @Component trong đó có 3 thuộc tính selector, templateURL và styleUrls.
Trong đó:
- selector dùng để chỉ ra DOM element nào mà component này sử dụng. Chúng ta thấy selector tên là app-root. Trong trường hợp bất kỳ nếu chúng ta nhúng thẻ <app-root></app-root> vào template đều được compiled bằng AppRootComponent và nhận bất kỳ tính năng đính kèm nào.
Như vậy thẻ <app-root></app-root> này sẽ chứa đựng giao diện html của App Component. Trong html thông thường thì không có thẻ thẻ này do chính chúng ta định nghĩa ra.
- templateUrl : trong component, chúng ta có chỉ định ‘./app.component.html” điều đó có nghĩa là sẽ load template từ file app.component.html trong cùng một directory với component.
- styleUrls : Tương tự templateUrl, chúng ta cũng chỉ định [‘./app.component.css], điều này có nghĩa là chúng ta sẽ sử dụng CSS trong file app.component.css cho component này.
Khi chạy ng -server -o ta sẽ thấy được giao diện HTML được định nghĩa trong templateURL là file app.component.html như sau:
Giờ mình sẽ điểm qua những tính năng cơ bản của Angular
– Template
- Khi mà các view trong html trở nên phức tạp hoặc được dùng đi dùng lại trong Angular thì khi đó template sẽ để giải quyết được vấn đề. View thường được sắp xếp phân cấp, cho phép bạn sửa đổi hoặc hiển thị và ẩn toàn bộ các phần trong giao diện.
- Hệ thống view phân cấp có thể bao gồm các view từ các component trong cùng một NgModule, nhưng cũng có thể bao gồm view từ các component được xác định trong các NgModule khác.
Template về cơ bản như HTML thông thường, ngại trừ việc chứa cú pháp template Angular, cú pháp này thay đổi HTML dựa trên logic của ứng dụng của bạn và trạng thái của ứng dụng và dữ liệu của DOM.
Ví dụ một template:
Template ở trên sử dụng các phần tử HTML điển hình như <div> , <h3> , <p> , bên cạnh đó cũng bao gồm các phần tử cú pháp template của Angular như *ngFor , {{ data.name }} , {{ data.age }} , (click), [personInfo] , <app-data-person>. Các phần tử cú pháp template cho Angular biết cách hiển thị HTML ra màn hình sử dụng dữ liệu và logic của chương trình.
– Data binding
Databinding là kỹ thuật nơi dữ liệu được đồng bộ giữa component và tầng view (template file html). Ví dụ khi người dùng cập nhật data ở tầng view thì Angular cũng cập nhật giá trị đó ở component.
Angular hỗ trợ data binding hai chiều, một cơ chế để phối hợp các phần của một framework với các phần của một component.
+ One way binding
- One way binding được hiểu là dữ liệu được truyền 1 chiều. Có thể từ view sang component hoặc ngược lại từ component sang view.
- Từ component sang view chúng ta sử dụng Property Binding để hiển thị dữ liệu như sau:
- Chúng ta sử dụng để hiển thị giá trị từ component sang view.
Ví dụ ta có component là
Như vậy dữ liệu trong component này ta hiển thị bên View như sau:
- Ngược lại nếu từ view truyền dữ liệu về component thì ta dùng Property binding như sau [disabled]=”isDisabled”.
- Event Binding chúng ta sử dụng để bind các sự kiện như click chuột, sự kiện bàn phím etc. Để xử dụng ta dùng cú pháp sau để thực hiện sự kiện khi chuột click vào nút Save. Sau đó nó sẽ gọi hàm showStatus bên class component.
+Two way binding
Two way binding cho phép các components trong ứng dụng chia sẻ dữ liệu bằng cách lắng nghe các sự kiện và cập nhật giá trị đồng thời giữa các components cha và con.
Cú pháp Two way binding của Angular là sự kết hợp của dấu ngoặc vuông và dấu ngoặc đơn [()], cú pháp kết hợp của property binding [] và event binding () như dưới.
– Service
Angular Service là những đoạn code mà ta có thể sử dụng nhiều lần từ các component khác nhau. Những đoạn code này sẽ thực hiện một nhiệm vụ cụ thể cho một ý định nào đó.
Chúng ta có thể sử dụng service cho những mục đích:
- Gọi API truyền data từ backend hoặc từ bên ngoài.
- Chia sẻ code logic hoặc data để các component có thể dùng chung.
Ưu điểm của Service:
- Dễ dàng truy cập các phương thức và thuộc tính trên các component khác trong toàn bộ dự án.
- Dễ dàng debugs khi có vấn đề.
- Có thể được sử dụng lại ở nhiều module.
Ví dụ về một service AppLogService có nhiệm vụ log ra browser console:
– Dependency Injection
Dependency Injection (DI) được tích hợp sẵn và là một phần quan trọng trong bộ core của Angular. Sử dụng cơ chế Dependency Injection giúp chúng ta có thể nhúng service vào các component hoặc các service khác nhau để có thể truy cập vào lớp service đó.
Angular tạo một instance mới của một lớp component, nó sẽ xác định service hoặc các dependency khác mà các component cần bằng cách xem các tham số của phương thức khởi tạo.
Khi Angular phát hiện một component phụ thuộc vào một service được chỉ định, trước tiên sẽ kiểm tra xem injector có bất kỳ instance nào hiện có của service đó hay không.
Ví dụ quá trình inject service AppLogService trong phương thức constructor của component dưới đây:
Nếu một instance của service được yêu cầu chưa tồn tại, injector tạo một instance bằng cách sử dụng provider đã đăng ký và thêm vào injector trước khi trả lại instance của service.
Khi tất cả các service được yêu cầu đã được khởi tạo và trả về, Angular có thể gọi hàm khởi tạo của component với instance của các service đó làm đối số.
Ví dụ sử dụng AppLogService trong AppDataPersonComponent:
Phía trên ta có phương thức getLog() gọi tới service AppLogService thông qua Injector được chỉ định là logService.
Chung quy lại thì Dependency Injection được sử dụng nhiều trong dự án Angular để thông qua đó ta có thể gọi tới service hoặc đoạn mã đã chỉ định trước đó.