Ở hướng dẫn trước, bạn sẽ tìm hiểu kiến trúc ứng dụng Angular, cấu trúc một dự án Angular, định tuyến và điều hướng ứng dụng Angular. Nếu bạn bỏ lỡ hướng dẫn này thì có thể xem ở bài viết sau:
Angular có một module dành riêng cho điều hướng và định tuyến là RouterModule
. Với module này, bạn có thể tạo các tuyến, cho phép bạn di chuyển từ phần này của ứng dụng sang phần khác hoặc từ view này sang view khác.
Để các tuyến hoạt động, bạn cần một liên kết hoặc phần tử trong giao diện người dùng để ánh xạ các hành động (thường là nhấp vào các phần tử) đến các tuyến (đường dẫn URL).
Chúng tôi sử dụng directive routerLink
cho mục đích này. Ví dụ: khi người dùng nhấp vào tên danh mục trong giao diện người dùng, thông qua directive routerLink
Angular biết rằng nó cần điều hướng đến url sau: http://localhost:4200/questions/about/category-name
<a class="list-title" [routerLink]="['/questions/about', category.slug]">{{category.title}}</a>
Tiếp theo, bạn sẽ cần ánh xạ các đường dẫn URL đến các component. Trong cùng thư mục với module gốc, hãy tạo tệp cấu hình có tên app.routes.ts
(nếu bạn chưa có) với mã sau.
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
component: CategoriesComponent,
resolve: {
data: CategoriesResolver
}
},
{
path: 'questions/about/:categorySlug',
component: CategoryQuestionsComponent,
resolve: {
data: CategoryQuestionsResolver
}
},
{
path: 'question/:questionSlug',
component: QuestionAnswersComponent,
resolve: {
data: QuestionAnswersResolver
}
}
];
Đối với mỗi tuyến, chúng tôi cung cấp một đường dẫn (còn được gọi là URL) và thành phần sẽ được hiển thị tại đường dẫn đó. Chuỗi trống cho đường dẫn CategoriesComponent
có nghĩa là CategoriesComponent sẽ được hiển thị khi ở đường dẫn gốc.
Lưu ý rằng đối với mỗi tuyến chúng tôi cũng có cách giải quyết. Sử dụng giải pháp trong các tuyến điều hướng của chúng tôi cho phép chúng tôi tìm nạp trước dữ liệu của component trước khi tuyến được kích hoạt. Sử dụng các resolver là một thực hành rất tốt để đảm bảo rằng tất cả dữ liệu cần thiết đã sẵn sàng cho các component của chúng ta sử dụng và tránh hiển thị một component trống trong khi chờ dữ liệu.
Ví dụ, chúng ta sử dụng CategoriesResolver
để tìm nạp danh sách các danh mục. Khi các danh mục đã sẵn sàng, chúng ta kích hoạt tuyến. Xin lưu ý rằng nếu quá trình giải quyết Observable không hoàn tất, quá trình điều hướng sẽ không tiếp tục.
Cuối cùng, module gốc cũng phải biết các tuyến mà chúng tôi đã định nghĩa ở trên. Thêm tham chiếu đến các tuyến trong thuộc tính import của AppModule
.
import { routes } from './app.routes';
imports: [
RouterModule.forRoot(routes,
{ useHash: false }
)
],
Lưu ý cách chúng tôi sử dụng các phương thức forRoot
(hoặc forChild
cuối cùng) trên RouterModule
(tài liệu giải thích sự khác biệt một cách chi tiết, nhưng bây giờ chỉ cần biết rằng forRoot
chỉ nên được gọi một lần trong ứng dụng của bạn cho các tuyến cấp cao nhất).
Có một số thư viện cung cấp các component cấp cao cho phép bạn nhanh chóng tạo giao diện đẹp cho ứng dụng của mình. Chúng bao gồm các phương thức, cửa sổ bật lên, thẻ, danh sách, menu, v.v. Chúng là các phần tử giao diện người dùng có thể tái sử dụng đóng vai trò là khối xây dựng cho ứng dụng dành cho thiết bị di động của bạn, được tạo thành từ HTML, CSS và đôi khi là JavaScript.
Hai trong số các thư viện thành phần UI được sử dụng nhiều nhất là Angular Material và ngx-bootstrap. Angular Material là thư viện Angular UI chính thức và cung cấp rất nhiều component.
Mặt khác, ngx-bootstrap cung cấp một loạt các component Angular được tạo trên nền tảng Twitter Bootstrap framework.
Trong hướng dẫn Angular này, chúng ta sẽ sử dụng Angular Material, nhưng hãy thoải mái chọn cái phù hợp nhất với nhu cầu của bạn vì chúng đều siêu hoàn chỉnh và mạnh mẽ.
Trong ứng dụng Angular này, chúng ta có các bố cục khác nhau. Đối với mỗi view, chúng ta cần các component giao diện người dùng khác nhau. Đây là danh sách ngắn với các component quan trọng nhất mà chúng tôi đã sử dụng cho mỗi view và liên kết đến các chi tiết cụ thể của việc triển khai view đó.
View Categories:
View Question:
View Answer:
Modal Câu hỏi mới và Câu trả lời mới:
Chúng tôi cũng đã sử dụng Angular Material Toolbar Component cho điều hướng breadcrumbs.
Vui lòng tìm hiểu thư viện các component giao diện người dùng mà Angular Material có trong trang tài liệu thành phần của họ.
Chìa khóa cho một ứng dụng đang phát triển là tạo ra các dịch vụ có thể sử dụng lại để quản lý tất cả các cuộc gọi dữ liệu đến backend của bạn.
Như bạn có thể đã biết, có nhiều cách để xử lý dữ liệu và triển khai backend. Trong hướng dẫn này, chúng tôi sẽ giải thích cách sử dụng dữ liệu từ tệp json tĩnh với dữ liệu giả. Trong hướng dẫn tìm hiểu cách xây dựng ứng dụng ngăn xếp MEAN, bạn sẽ tìm hiểu cách xây dựng và sử dụng dữ liệu từ REST API với Loopback (một framework node.js hoàn toàn phù hợp với REST API) và MongoDB (để lưu trữ dữ liệu).
Cả hai triển khai (json tĩnh và backend API từ xa) đều cần phải quan tâm về khía cạnh vấn đề của ứng dụng, cách xử lý các cuộc gọi dữ liệu. Điều này hoạt động giống nhau và độc lập về cách bạn triển khai backend. Chúng ta sẽ nói về các model và service và cách chúng làm việc cùng nhau để đạt được điều này.
Chúng tôi khuyến khích việc sử dụng các model kết hợp với các service để xử lý dữ liệu từ backend đến luồng trình bày.
Mô hình miền (domain model) rất quan trọng để xác định và thực thi logic nghiệp vụ trong các ứng dụng và đặc biệt có liên quan khi các ứng dụng trở nên lớn hơn và nhiều người làm việc trên chúng hơn.
Đồng thời, điều quan trọng là chúng ta phải giữ cho các ứng dụng của mình DRY và có thể bảo trì bằng cách chuyển logic ra khỏi các component và vào các lớp (model) riêng biệt có thể được gọi.
Một cách tiếp cận module như thế này, làm cho business logic của ứng dụng của chúng ta có thể tái sử dụng.
Angular cho phép bạn tạo nhiều dịch vụ dữ liệu (data service) có thể tái sử dụng và đưa chúng vào các component cần chúng. Cấu trúc lại quyền truy cập dữ liệu vào một service riêng biệt, giữ cho component gọn gàng và tập trung vào việc hỗ trợ view. Nó cũng giúp kiểm thử đơn vị (unit testing) component dễ dàng hơn bằng cách sử dụng mock service.
Trong trường hợp của chúng tôi, chúng tôi đã định nghĩa một model cho dữ liệu danh mục câu hỏi mà chúng tôi đang lấy từ tệp json tĩnh. Model này được sử dụng bởi categories.service.ts
.
//in category.model.ts
export class CategoryModel {
slug: string;
title: string;
image: string;
description: string;
tags: Array<Object>;
}
//in categories.service.ts
getCategories(): Promise<CategoryModel[]> {
return this.http.get("./assets/categories.json")
.toPromise()
.then(res => res.json() as CategoryModel[])
}
Và chúng tôi sử dụng service này ở categories.resolver.ts
, nơi chúng tôi tìm nạp dữ liệu lên View Categories.
//in categories.resolver.ts
import { Injectable } from '@angular/core';
import { Resolve } from "@angular/router";
import { CategoriesService } from "../services/categories.service";
@Injectable()
export class CategoriesResolver implements Resolve<any> {
constructor(private categoriesService: CategoriesService) { }
resolve() {
return new Promise((resolve, reject) => {
let breadcrumbs = [
{ url: '/', label: 'Categories' }
];
//get categories from local json file
this.categoriesService.getCategories()
.then(
categories => {
return resolve({
categories: categories,
breadcrumbs: breadcrumbs
});
},
err => {
return resolve(null);
}
)
});
}
}
Mỗi khi chúng ta thêm một service mới, hãy nhớ rằng Angular injector sẽ không biết cách tạo service đó theo mặc định. Nếu chúng ta chạy mã của mình ngay bây giờ, Angular sẽ báo lỗi. Sau khi tạo các service, chúng ta phải hướng dẫn Angular injector cách tạo service đó bằng cách đăng ký Service provider.
Theo trang tài liệu Angular về dependency injection, có hai cách để đăng ký Service provider: trong chính Component hoặc trong Module (NgModule). Trong trường hợp của chúng tôi, chúng tôi đăng ký tất cả các dịch vụ trong app.module.ts
//in app.module.ts
@NgModule({
declarations: [
AppComponent,
CategoriesComponent,
CategoryQuestionsComponent,
NewQuestionModalComponent,
NewAnswerModalComponent,
UpdateAnswerModalComponent,
QuestionAnswersComponent,
DeleteQuestionModalComponent,
DeleteAnswerModalComponent
],
imports: [
RouterModule.forRoot(routes,
{ useHash: false }
),
SharedModule
],
entryComponents: [
],
providers: [
CategoriesService,
QuestionsService,
AnswersService,
CategoryQuestionsResolver,
CategoriesResolver,
QuestionAnswersResolver
],
bootstrap: [AppComponent]
})
export class AppModule { }
Một lưu ý nhỏ về tầm quan trọng của Dependency Injection từ nguyên tắc kiến trúc phần mềm: Hãy nhớ rằng chúng ta vừa đề cập rằng chúng ta "inject" các data service vào các component cần chúng? Khái niệm này được gọi là Dependency Injection.
Vì sao nên làm như vậy thay vì khởi tạo trực tiếp service trong component:
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
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.
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.
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.
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.