Hướng dẫn Angular 2: Tạo CRUD App bằng Angular CLI

4289

Đây là bài viết đầu tiên trong series 4 bốn phần hướng dẫn cách viết một ứng dụng Todo (quản lý công việc) trong Angular 2:

  1. Part 1— Cài đặt và khởi chạy phiên bản ứng dụng Todo đầu tiên
  2. Part 2— Tạo các thành phần khác nhau để hiển thị list trong todo và todo riêng biệt
  3. Part 3— Cập nhật dịch vụTodo để giao tiếp REST API
  4. Part 4— Dùng Component Router để định tuyết các thành phần khác nhau

Chú thích: ứng dụng todo là một ứng dụng đơn giản nhắc nhở một loạt công việc cần làm trong ngày/tuần, với mỗi todo là một công việc phải hoàn thành.

Trong bài viết này, chúng ta sẽ đi sâu vào cấu trúc cơ bản của ứng dụng để cho ra đời một ứng dụng trông như sau:

Đến cuối series này, cấu trúc ứng dụng của chúng ta sẽ như sau:

Những mục được bảo đỏ sẽ được nhắc đến trong bài viết này, những khái niệm còn lại sẽ được giới thiệu trong các bài viết sau của series.

Trong phần đầu tiên này, bạn được hướng dẫn cách:

  • Khởi tạo ứng dụng Todo bằng Angular CLI
  • Tạo class Todo để thể hiện các mục todo riêng biệt
  • Tạo dịch vụ TodoDataService để tạo, cập nhật và bỏ mục todo
  • Dùng thành tố AppComponent để hiển thị giao diện người dùng
  • Deploy ứng dụng đến page GitHub của bạn

Bắt đầu nhé!

Khởi tạo ứng dụng Todo bằng Angular CLI

Một trong những cách bắt đầu một ứng dụng Angular 2 tốt nhất là dùng command-line interface (CLI) của Angular.

Để cài đặt Angular CLI, chạy:

Đoạn trên sẽ cài đặt lệnh ng gobal lên hệ thống.

Để xác nhận xem quá trình cài đặt đã thành công hay chưa, bạn có thể chạy:

Đoạn lệnh trên sẽ hiển thị phiên bản bạn đã cài đặt:

Sau khi đã cài đặt Angular CLI, bạn đã có thể sử dụng công cụ để khởi tạo ứng dụng Todo của mình:

Đoạn lệnh này sẽ tạo một thư mục mới với tất cả những file cần thiết để bắt đầu:

todo-app
├── README.md
├── angular-cli.json
├── e2e
│   ├── app.e2e-spec.ts
│   ├── app.po.ts
│   └── tsconfig.json
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── src
│   ├── app
│   │   ├── app.component.css
│   │   ├── app.component.html
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   ├── app.module.ts
│   │   └── index.ts
│   ├── assets
│   ├── environments
│   │   ├── environment.prod.ts
│   │   └── environment.ts
│   ├── favicon.ico
│   ├── index.html
│   ├── main.ts
│   ├── polyfills.ts
│   ├── styles.css
│   ├── test.ts
│   ├── tsconfig.json
│   └── typings.d.ts
└── tslint.json

Nếu vẫn chưa quá quen thuộc với Angular CLI, bạn có thể đọc thêm tại The Ultimate Angular CLI Reference.

Giờ đây bạn đã có thể điều hướng đến thư mục mới:

Và khởi động được Angular CLI development server:

Đoạn lệnh sẽ khởi động local development server truy cập được từ trình duyệt http://localhost:4200/.

Angular CLI development server có hỗ trợ LiveReload, nên mỗi khi file nguồn thay đổi trình duyệt sẽ tự động tải lại ứng dụng.

Tiện quá các bạn nhỉ?

Tạo Todo Class

Vì Angular CLI tạo được file TypeScript, chúng ta có thể dùng class để thể hiện mục todo:

Chúng ta hãy thử dùng Angular CLI để tạo class Todo nhé:

Đoạn lệnh sẽ tạo:

Hãy mở src/app/todo.ts:

Và thêm logic ta cần:

Trong Todo class definition này, chúng ta sẽ chỉ định rằng mỗi instance Todo có 3 tính chất:

  • id: số, ID chuyên biệt của todo item
  • title: string, tên của todo item
  • complete: boolean,todo item đã hoàn thành hay chưa

Chúng ta còn phải cung cấp logic hàm dựng cho phép chỉ định property value trong quá trình thực thể hóa (instantiation) để có thể dễ dàng tạo được những instance Todo mới như sau:

Đến đây, hãy thêm unit test để đảm bảo constructor logic của chúng ta làm việc như dự đoán.

Khi tạo class Todo, ta đã dùng tùy chọn --spec. Tùy chọn này sẽ khiến Angular CLI cũng tạo thêm src/app/todo.spec.ts với unit test cơ bản cho ta luôn:

Hãy thêm vào unit test nữa để đảm bảo constructor logic làm việc đúng như dự đoán:

Để xác định xem code của chúng ta đã đúng hay chưa, giờ đây ta sẽ chạy:

để thực thi Karma test runner và chạy tất cả unit test ta cần. Out của bạn sẽ như sau:

Sau khi ta đã có class Todo hoạt động được để thể hiện một todo riêng biệt, tiếp đến hãy tạo service TodoDataService để quản lý tất cả mục todo.

Tạo TodoDataService Service

TodoDataService sẽ đảm nhận nhiệm vụ quản lý Todo item.

Trong các phần tiếp theo của series, chúng ta sẽ tìm hiểu các giao tiếp với EST API, nhưng lúc này chúng ta sẽ chỉ lưu trữ tất cả dữ liệu trong bộ nhớ.

Hãy sử dụng Angular CLI lần nữa để tạo service:

Với output:

Khi tạo service, Angular CLI cũng tạo thêm unit test theo mặc định, nên ta không cần phải dùng thêm tùy chọn --spec.

Angular CLI đã tạo đoạn code sau cho TodoDataService của ta trong src/app/todo-data.service.ts:

Và một unit test tương ứng trong src/app/todo-data.service.spec.ts:

Hãy mở src/app/todo-data.service.ts và thêm todo management logic của chúng ta vào TodoDataService:

Chi tiết thực tế về việc implement method không cần thiết lắm khi xét đến mục đích của bài viết này. Bài học chủ yếu được rút ra là, chúng ta phải đặt business logic làm trung tâm của service.

Để đảm bảo business logic trong service TodoDataService làm việc như mong đợi, chúng ta cũng phải thêm một số unit test trong src/app/todo.service.spec.ts:

Hãy đi sâu hơn nữa vào một số phần trong unit test bên trên:

Trước hết, TestBed là gì?

TestBed là tiện ích do @angular/core/testing cung cấp để tinh chỉnh và tạo Angular testing module để ta có thể chạy unit test trong đó.

Chúng ta sử dụng method TestBed.configureTestingModule() để configure và tạo Angular testing module mới. Chúng ta có thể configure testing module theo như ý thích bằng cách pass in một configuration object. Configuration object này có hầu hết tính chât của một Angular module thông thường.

Trong trường hợp này chúng ta có thể dùng tính chất providers để tinh chỉnh testing module để dùng TodoDataService thạt sự khi chạy test.

Kế tiếp, chúng ta sẽ dùng hàm inject do @angular/core/testing cung cấp để inject đúng service từ TestBed injector vào hàm test của chúng ta:

Argument đầu tiên của hàm inject là một array của Angular dependency injection tokens. Argument thứ hai là hàm test có tham số là các dependency tương ứng với dependency injection token từ array.

Tại đây chúng ta yêu cầu TestBed injector phải inject TodoDataService bằng cách chỉ định trong array trong argument đầu tiên. Như vậy, chúng ta có thể tận dụng TodoDataService làm service trong hàm test vì service là tên của tham số đầu tiên trong hàm test của chúng ta.

Để xác định xem service của chúng ta có làm việc như kỳ vọng hay không, chạy unit test một lần nữa:

Hoàn hảo, tất cả unit test đã chạy thành công!

Giờ đây là đã có serviceTodoDataService chạy tốt, đã đến lúc xây dựng giao diện người dùng.

Trong Angular 2, các phần trong giao diện người dùng được components thể hiện.

Chỉnh sửa component AppComponent

Khi chúng ta khời tạo ứng dụng Todo, Angular CLI tự động tạo component chính AppComponent cho chúng ta:

Hãy mở src/app/app.component.html:

Và thay thế nội dung của nó với:

Dưới đây là phần giới thiệu siêu ngắn các cú pháp mẫu trong Angular nếu bạn bạn nào vẫn chưa xem:

  • [property]="expression": set thuộc tính của một element đến giá trị biểu thức (value of expression)
  • (event)="statement": thực thi câu lệnh khi event xảy ra
  • [(property)]="expression": tạo two-way binding với expression
  • [class.special]="expression": thêm class CSS đặc biệt vào element khi giá trị biểu thức đúng (truthy)
  • [style.color]="expression": set tính chất color CSS đến giá trị biểu thức

Hãy cùng xem thử những cú pháp này sẽ làm gì với giao diện của chúng ta nhé. Tại trên cùng, sẽ có một ô input để tạo todo mới:

  • [(ngModel)]="newTodo.title": thêm two-way binding giữa input value và newTodo.title
  • (keyup.enter)="addTodo()": yêu cầu Angular thực thi addTodo() nhấn enter trong lúc gõ input element.

(Hẳn bạn đang tự hỏi newTodo với addTodo() từ đâu mà ra, chúng ta sẽ nói về vấn đề này sớm thôi.)

Kế tiếp, ta sẽ đến phần hiển thị todo hiện có:

*ngIf="todos.length > 0": chỉ hiển thị element section element và các element con tại những điểm có ít nhất một todo.

Trong phần đó, chúng tôi đã yêu cầu Angular tạo một element li cho mỗi todo:

  • *ngFor="let todo of todos": loop khắp tất cả todo và chỉ định todo hiện hành đến một biến variable với tên todo với mỗi lần lặp lại
  • [class.completed]="todo.complete": áp dụng CSS class complete đến element li khi todo.complete đúng (truthy)

và cuối cùng, chúng ta sẽ hiểu thị chi tiết cần làm cho mỗi todo:

  • (click)="toggleTodoComplete(todo)": thực thi toggleTodoComplete(todo) và checkbox được click
  • [checked]="todo.complete": chỉ định giá trị của todo.complete đến tính chất checked của element
  • (click)="removeTodo(todo)": thực thi removeTodo(todo) khi click vào nút destroy

OK, thở chút đã. Nãy giờ chúng ta đã tìm hiểu được quá trời cú pháp rồi đấy.

Nhiều người thắc mắc tại sao những như addTodo() and newTodo.title có thể được đánh giá. Và component instance là instance của component class.

Component class cho AppComponent được xác định trong src/app/app.component.ts.

Angular CLI đã tạo trước một ít boilerplate code.

Vậy nên chúng ta có thể ngay lập tức bắt đầu thêm custom logic.

Chúng ta sẽ cần service TodoDataService trong logic AppComponent, nên hãy bắt đầu bằng cách inject service vào componet.

Trước hết chúng ta sẽ import TodoDataService và xác định array providers của decorator Component.

Dependency injector AppComponent giờ sẽ nhận class TodoDataService làm dependency injection token và trả kết quả là instance duy nhất của TodoDataService.

Giờ thì dependency injector đã biết nó phải làm gì, chúng ta sẽ yêu cầu nó inject instance TodoDataService của cúng ta vào component bằng cách chỉ định dependency trong constructor AppComponent:

Việc sử dụng public or private trên argument trong constructor là ký hiệu viết tắt cho phép chúng ta tự động tạo tính chất với tên này, vì vậy:

là viết tắt của:

Chúng ta giờ đây có thể implement tất cả view logic bằng cách thêm tính chất và method vào class AppComponent:

Chúng ta trước hết sẽ xác định một tính chất newTodo và gán new Todo() khi component class được thực thể hóa. Đây là cùng một instance Todo được xác định trong biểu thức của [(ngModel)]:

Ngay khi input value thay đổi trong view, giá trị trong component instance được cập nhật. Và mỗi khi giá trị trong component instance thay đổi, giá trị trong input element trong view sẽ được cập nhật.

Kế tiếp, chúng ta sẽ implement tất cả method ta đã dùng trong view:

Quá trình implement diễn ra rất ngắn, và phải thật dễ hiểu khi ủy nhiệm tất cả business logic cho todoDataService.

(Ủy nhiệm business logic cho một service service là thói quen lập trình rất có lợi vì chúng ta có thể quản lý và test .)

Trước khi xem thử kết quả trên trình duyệt, hãy chạy unit test một lần nữa:

Ba test thất bại vì lỗi sau: an't bind to 'ngModel' since it isn't a known property of 'input'..

Hãy mở src/app/app.component.spec.ts lên:

Lý do Angular phàn nàn nó không biết ngModel là vì FormsModule không được load khi AppComponent được thực thể hóa bở Karma bằng method TestBed.createComponent().

(Để tìm hiểu thêm TestBed, bạn nên đọc thêm Official Angular documentation on testing.)

Để đảm bảo Angular cũng có load FormsModule khi Karma thực thể hóa AppComponent bằng TestBed.createComponent(), chúng ta phải chỉ định FormsModule trong tính chất imports của Testbed configuration object:

Chúng ta giờ lại có 2 test thất bại:

Karma có cảnh báo chúng ta rằng component instance không có title tính chất bằng với app works! và rằng không có element h1 chứa app works!.

Như thế là đúng bởi vì chúng ta đã thay đổi component logic và template. Vậy nên hãy cập nhật unit tests cho phù hợp:

Chúng ta trước hết sẽ thêm unit test để đảm bảo tính chất newTodo được thực thể hóa đúng cách:

Và sau đó thêm một unit test nữa để đảm bảo element h1 có chứa string cần thiết:

Bạn có thể thoải mái thử nghiệm với bản live demo để xem thử trước kết quả.

Trước khi đóng lại bài viết, hãy tìm hiểu tính năng nữa rất hay của Angular CLI.

Deploy đến GitHub Pages

Angular CLI giúp ta deploy ứng dụng lên GitHub Pages thật đơn giản, chỉ với một dòng lệnh duy nhất:

Lệnh github-pages:deploy sẽ yêu cầu Angular CLI xây dựng phiên bản ứng dụng tĩnh và push lên nhánh gh-pages của GitHub repo:

Ứng dụng của chúng ta giờ đã có mặt trên https://sitepoint-editors.github.io/todo-app/.

Thật tuyệt phải không!?

Tóm tắt

Không còn nghi ngờ gì nữa, Angular 2 là một công cụ tốt, tốt đến đáng sợ!

Trong phạm vi bài viết, chúng ta đã tìm hiểu về:

  • Cách bắt đầu một ứng dụng Angular hoàn toàn mới với Angular CLI
  • Cách implement business logic trong Angular service và cách test business logic với unit tests
  • Cách dùng component để tương tác với user và cách ủy nhiện logic cho service thông qua dependency injection
  • Cấu trúc mẫu Angular cơ bản, da lông về cách làm việc của Angular dependency injection
  • Cuối cùng, chúng ta đã học được cách nhanh chóng deploy ứng dụng lên GitHub Pages

Trong phần tiếp theo, chúng ta sẽ tìm hiểu cách tạo components riêng biệt để hiển thị một loạt todo và chi tiết cho từng todo.

Techtalk via sitepoint

 

CHIA SẺ