Nói thật với bạn, cái nghề lập trình viên này nó có một cái hay là không ngừng thay đổi. Đặc biệt là với một framework năng động như Angular, việc giữ mình luôn cập nhật và chuẩn bị sẵn sàng cho mọi thử thách là cực kỳ quan trọng. Tôi đã đi qua không ít buổi phỏng vấn, chứng kiến nhiều bạn trẻ tài năng rồi cũng thấy cả những trường hợp tiếc nuối. Từ những ngày đầu tiên của AngularJS cho đến bây giờ với những phiên bản Angular hiện đại, mỗi giai đoạn đều có những cái “móc” kiến thức cần phải nắm vững.
Angular, một framework TypeScript mạnh mẽ được chính Google đỡ đầu, đã trở thành xương sống cho vô số ứng dụng web phức tạp. Tại sao nó lại được ưa chuộng đến vậy? Đơn giản là vì hiệu suất cao, cấu trúc bài bản và một cộng đồng hỗ trợ cực kỳ lớn mạnh. Điều này cũng lý giải vì sao nhu cầu tuyển dụng các bạn lập trình viên Angular trên thị trường vẫn luôn nóng hổi. Để giúp bạn tự tin sải bước vào thế giới ấy, tôi muốn chia sẻ bộ câu hỏi phỏng vấn Angular từ cơ bản đến nâng cao, cùng với những kinh nghiệm thực chiến mà tôi đã đúc kết được. Nó sẽ giúp bạn không chỉ trả lời tốt các câu hỏi phỏng vấn Angular Developer mà còn biết cách “ghi điểm” với nhà tuyển dụng nữa đấy.
1. Nắm Vững Kiến Thức Nền Tảng: Câu Hỏi Angular Cho Fresher & Intern
Khi bạn mới chập chững bước vào nghề, hoặc đang là một intern, fresher, nhà tuyển dụng thường muốn kiểm tra xem bạn có nắm chắc những khái niệm cơ bản nhất không. Đây là lúc để bạn thể hiện sự hiểu biết về nền tảng, những viên gạch đầu tiên xây nên một ứng dụng Angular.
1.1. Hiểu Rõ Angular & TypeScript
Trước hết, chúng ta phải nói về Angular là gì. Nó không chỉ là một thư viện nhỏ bé mà là một framework toàn diện, cung cấp mọi thứ bạn cần để xây dựng ứng dụng web một trang (SPA) mạnh mẽ. Nó mang đến một cấu trúc rõ ràng, hỗ trợ phát triển theo kiểu mẫu khai báo (declarative patterns), cơ chế chèn phụ thuộc (dependency injection) thông minh và cả các công cụ end-to-end nữa.
-
Angular Framework là gì?
Như tôi đã nói, Angular là một nền tảng phát triển ứng dụng web phía client. Nó dùng TypeScript, một siêu tập hợp của JavaScript, và được phát triển, duy trì bởi một đội ngũ kỹ sư tại Google. Mấy tính năng cốt lõi của nó như cấu trúc module, component, service giúp việc quản lý code trở nên dễ dàng và hiệu quả hơn rất nhiều.
-
Phân biệt AngularJS và Angular: Sự Khác Biệt Cốt Lõi
Đây là câu hỏi kinh điển luôn. AngularJS (phiên bản 1.x) và Angular (phiên bản 2 trở lên) là hai thứ hoàn toàn khác biệt, giống như hai anh em sinh đôi nhưng mỗi người một tính cách vậy. AngularJS dùng JavaScript, còn Angular dùng TypeScript. Kiến trúc của AngularJS dựa trên khái niệm Scope và Controller, trong khi Angular đi theo hướng Component-based mạnh mẽ hơn. Về hiệu suất và khả năng hỗ trợ di động, Angular vượt trội hơn hẳn. Hồi chuyển đổi từ AngularJS sang Angular là cả một cuộc cách mạng trong cộng đồng đấy.
-
TypeScript là gì và tại sao Angular ưu tiên sử dụng TypeScript?
TypeScript về cơ bản là JavaScript có thêm kiểu dữ liệu tĩnh. Nghe thì có vẻ rườm rà nhưng thực tế, nó giúp dự án lớn của chúng ta an toàn hơn rất nhiều, giảm thiểu lỗi runtime. Nhờ có kiểu dữ liệu, bạn có thể dễ dàng phát hiện lỗi ngay khi code, chứ không phải đợi đến lúc chạy ứng dụng mới thấy. Nó cũng giúp các IDE (như VS Code) thông minh hơn, gợi ý code chuẩn hơn. Việc cài đặt cũng đơn giản lắm, chỉ cần `npm install -g typescript` là xong. Chẳng hạn, một hàm `greeter` trong TypeScript có thể được định nghĩa kiểu rõ ràng:
function greeter(person: string) { return "Hello, " + person; } let user = "Jane User"; console.log(greeter(user));
1.2. Các Thành Phần Chính và Vòng Đời Component
Để xây dựng một ứng dụng Angular, bạn cần hiểu rõ những viên gạch cơ bản tạo nên nó:
-
Liệt kê và giải thích các thành phần chính của Angular:
- Component: Đây là khối xây dựng cơ bản nhất của giao diện người dùng, kiểm soát một phần HTML view cụ thể. Nó giống như một mảnh ghép lego lớn, mỗi component có nhiệm vụ riêng và có thể tái sử dụng.
- Module (NgModule): Là tập hợp các block xây dựng, giúp chia ứng dụng thành các phần logic. Nó khai báo những gì thuộc về nó (declarations), những gì nó cần (imports), những gì nó cung cấp (providers) và những gì nó muốn chia sẻ ra ngoài (exports).
- Template: Chính là phần HTML định nghĩa giao diện người dùng cho một component. Bạn có thể nhúng các biểu thức JavaScript nhỏ vào đây để hiển thị dữ liệu động.
- Service: Là nơi chứa các logic nghiệp vụ, xử lý dữ liệu hoặc giao tiếp với backend. Chúng được thiết kế để có thể chia sẻ trên toàn ứng dụng thông qua cơ chế Dependency Injection.
- Metadata: Là những thông tin bổ sung mà bạn gắn cho một class Angular (thường là qua decorator như `@Component`, `@NgModule`). Metadata nói cho Angular biết class đó đóng vai trò gì và cách nó tương tác với các phần khác của ứng dụng.
-
Mô tả tóm tắt vòng đời của một component trong Angular.
Mỗi component có một vòng đời riêng, từ lúc được tạo ra, được render lên DOM, được cập nhật, cho đến khi bị hủy bỏ. Angular cung cấp các “lifecycle hooks” để chúng ta có thể can thiệp vào các thời điểm này. Các hook phổ biến như:
- `ngOnChanges`: Được gọi khi giá trị của các input binding thay đổi.
- `ngOnInit`: Được gọi một lần duy nhất sau khi component được khởi tạo (và input binding đã được gán giá trị). Rất lý tưởng để khởi tạo dữ liệu.
- `ngDoCheck`: Được gọi thường xuyên để phát hiện các thay đổi mà Angular không thể tự động phát hiện.
- `ngAfterContentInit`: Được gọi sau khi nội dung được chiếu vào component được khởi tạo.
- `ngAfterContentChecked`: Được gọi sau mỗi lần kiểm tra nội dung được chiếu.
- `ngAfterViewInit`: Được gọi sau khi view của component và các view con được khởi tạo.
- `ngAfterViewChecked`: Được gọi sau mỗi lần kiểm tra view của component và các view con.
- `ngOnDestroy`: Được gọi ngay trước khi component bị hủy. Dùng để dọn dẹp tài nguyên, hủy đăng ký Observable.
-
ngModule là gì?
NgModule là một lớp được đánh dấu bằng decorator `@NgModule`, dùng để tổ chức mã nguồn của bạn. Nó định nghĩa cách các component, service, directive và pipe hoạt động cùng nhau trong một đơn vị chức năng. Trong `@NgModule`, chúng ta có:
- `declarations`: Khai báo các component, directive, pipe thuộc về module này.
- `imports`: Nhập các NgModule khác mà module này cần sử dụng (ví dụ: `BrowserModule`, `FormsModule`).
- `providers`: Đăng ký các service cung cấp cho module này hoặc toàn bộ ứng dụng.
- `exports`: Xuất các component, directive, pipe hoặc NgModule mà các module khác có thể sử dụng.
1.3. Cơ Chế Hoạt Động Cơ Bản
Hiểu được những cơ chế hoạt động ngầm của Angular sẽ giúp bạn debug tốt hơn và viết code hiệu quả hơn.
-
Phân biệt biến `let` và `var` trong JavaScript (liên quan đến phạm vi biến).

Mạng lưới kỹ thuật số trừu tượng màu xanh tím, tượng trưng cộng đồng nhà phát triển Angular mạnh mẽ và tăng trưởng hợp tác. Hình ảnh này nhấn mạnh tầm quan trọng của sự kết nối trong việc chuẩn bị cho các câu hỏi phỏng vấn Angular Developer. Đây là câu hỏi cơ bản của JavaScript nhưng rất quan trọng, đặc biệt khi dùng TypeScript. `var` có phạm vi là toàn bộ hàm (function scope) và có thể bị hoisting (kéo lên đầu hàm) với giá trị `undefined`. Ngược lại, `let` có phạm vi khối (block scope), tức là nó chỉ tồn tại trong khối `{}` mà nó được định nghĩa, và không bị hoisting một cách đầy đủ như `var` (nó vẫn bị hoisting nhưng rơi vào “temporal dead zone” nên không thể truy cập trước khi khai báo). `var` có thể tái khai báo và gán lại, còn `let` chỉ có thể gán lại mà không thể tái khai báo trong cùng một scope.
-
Cơ chế Angular phát hiện thay đổi giá trị binding là gì?
Angular sử dụng một cơ chế gọi là “Change Detection” để kiểm tra và cập nhật giao diện người dùng khi dữ liệu thay đổi. Mặc định, Angular sẽ kiểm tra mọi thứ từ trên xuống dưới (từ root component đến các component con) mỗi khi có một sự kiện nào đó xảy ra (click, HTTP request, timer). Công cụ đứng sau làm việc này phần lớn là `zone.js`, nó “patch” các API bất đồng bộ của trình duyệt để Angular biết khi nào cần chạy lại cơ chế phát hiện thay đổi.
-
Router trong Angular có tác dụng gì?
Router của Angular đóng vai trò cực kỳ quan trọng trong các ứng dụng SPA (Single Page Application). Nó giúp chúng ta định tuyến, tức là điều hướng người dùng giữa các “view” khác nhau mà không cần tải lại toàn bộ trang. Bạn có thể định nghĩa các path URL và mapping chúng với các component tương ứng. Hơn nữa, Router còn cho phép chúng ta:
- Lấy tham số trên URL (`ActivatedRoute`).
- Kiểm tra quyền truy cập route thông qua `Guard` (ví dụ: `CanActivate`, `CanDeactivate`).
-
Lazy-loading là gì và lợi ích của nó trong Angular?
Lazy-loading là một kỹ thuật tối ưu hóa hiệu suất. Thay vì tải toàn bộ code của ứng dụng khi vừa khởi động, Lazy-loading cho phép chúng ta chỉ tải những module hoặc component cần thiết khi người dùng thực sự yêu cầu đến chúng (ví dụ: khi điều hướng sang một route cụ thể). Lợi ích rõ ràng nhất là:
- Giảm thời gian tải ứng dụng ban đầu.
- Giảm dung lượng ứng dụng phải tải về, đặc biệt hữu ích trên các thiết bị di động hoặc mạng chậm.
1.4. Directives và Data Binding
Đây là những khái niệm cơ bản để bạn tương tác với DOM và dữ liệu trong Angular.
-
Bạn biết những gì về Directives trong Angular?
Directives là một cách để chúng ta gắn hành vi vào DOM hoặc sửa đổi DOM. Chúng có thể thay đổi cách hiển thị hoặc hoạt động của các phần tử HTML. Có hai loại chính:
- Structural Directives: Thay đổi cấu trúc của DOM bằng cách thêm, xóa hoặc sửa đổi các phần tử (ví dụ: `*ngIf`, `*ngFor`). Dấu `*` là một cú pháp đường tắt cho việc tạo `
`. - Attribute Directives: Thay đổi giao diện hoặc hành vi của một phần tử DOM đã có (ví dụ: `ngClass`, `ngStyle`).
Điểm khác biệt giữa `@Component` và `@Directive` là Component luôn có một template đi kèm, còn Directive thì không. Directive thường được dùng để thêm các tính năng tái sử dụng vào các phần tử DOM hiện có.
- Structural Directives: Thay đổi cấu trúc của DOM bằng cách thêm, xóa hoặc sửa đổi các phần tử (ví dụ: `*ngIf`, `*ngFor`). Dấu `*` là một cú pháp đường tắt cho việc tạo `
-
`ngFor` là gì? Nêu ví dụ về cách sử dụng.
`*ngFor` là một Structural Directive dùng để lặp qua một danh sách và render một phần tử HTML cho mỗi mục trong danh sách đó. Nó giống như một vòng lặp `for` trong template HTML.
<ul> <li *ngFor="let item of items">{{ item }}</li> </ul> -
`ngIf` là gì? Nêu ví dụ về cách sử dụng.
`*ngIf` cũng là một Structural Directive, dùng để hiển thị hoặc ẩn một phần tử HTML dựa trên một điều kiện. Nếu điều kiện là `true`, phần tử sẽ được thêm vào DOM; nếu `false`, nó sẽ bị xóa khỏi DOM.
<p *ngIf="isLoggedIn">Chào mừng bạn đã đăng nhập!</p> <button *ngIf="!isLoggedIn">Đăng nhập</button> -
Databinding One-way & Two-way khác nhau thế nào?
Data Binding là cách Angular kết nối dữ liệu từ component với view (HTML) và ngược lại. Có hai loại chính:
- One-way Data Binding: Dữ liệu chỉ chảy theo một hướng.
- Component to View (Interpolation `{{}}`, Property Binding `[]`): Dữ liệu từ component hiển thị lên view.
- View to Component (Event Binding `()`): Các sự kiện từ view (click, input change) được gửi về component.
- Two-way Data Binding: Dữ liệu chảy cả hai chiều (Component to View và View to Component) một cách tự động. Thay đổi ở component cập nhật view, và thay đổi ở view (ví dụ qua input) cũng cập nhật lại component. Cú pháp phổ biến là `[(ngModel)]`.
- One-way Data Binding: Dữ liệu chỉ chảy theo một hướng.
-
Interpolation là gì?
Interpolation là cách đơn giản nhất để hiển thị dữ liệu từ component lên template HTML. Bạn dùng cú pháp dấu ngoặc kép `{{ expression }}` để nhúng một biểu thức TypeScript vào HTML. Biểu thức này sẽ được Angular đánh giá và kết quả sẽ được hiển thị trên trình duyệt. Ví dụ: `{{ userName }}` sẽ hiển thị giá trị của biến `userName` từ component.
2. Đi Sâu Kiến Thức & Kỹ Năng: Câu Hỏi Phỏng Vấn Angular Nâng Cao
Nếu bạn đã có kinh nghiệm từ 3 năm trở lên, làm qua vài dự án, thì nhà tuyển dụng sẽ không chỉ hỏi bạn những thứ cơ bản nữa. Họ muốn thấy bạn có khả năng giải quyết vấn đề phức tạp, tối ưu hiệu suất và thiết kế kiến trúc ứng dụng như thế nào. Những câu hỏi phỏng vấn Angular Developer dưới đây sẽ thử thách bạn ở cấp độ cao hơn.

2.1. Quản Lý Dữ Liệu và Giao Tiếp Server
Việc quản lý dữ liệu và giao tiếp với backend là trái tim của mọi ứng dụng web.
-
Phân loại Data Binding chi tiết hơn?
Nếu đi sâu hơn, chúng ta có thể phân loại data binding dựa trên hướng dữ liệu:
- Source-to-view (Component to View): Dữ liệu từ component chảy đến view.
- Interpolation: `{{ expression }}`
- Property Binding: `[property]=”expression”`
- View-to-source (View to Component): Dữ liệu từ view chảy về component.
- Event Binding: `(event)=”statement”`
- View-to-source-to-view (Two-way Data Binding): Dữ liệu chảy hai chiều.
- Two-way Binding: `[(ngModel)]=”property”`
- Source-to-view (Component to View): Dữ liệu từ component chảy đến view.
-
Pipes là gì và lợi ích của chúng?
Pipes trong Angular là những hàm nhỏ mà bạn có thể dùng trong template để biến đổi dữ liệu trước khi hiển thị. Chúng rất hữu ích khi bạn muốn định dạng ngày tháng, tiền tệ, chữ hoa/thường hoặc cắt chuỗi. Chẳng hạn, `{{ birthday | date:’shortDate’ }}` sẽ định dạng ngày sinh. Lợi ích của Pipes là giúp mã nguồn template của bạn gọn gàng hơn, dễ đọc hơn và logic định dạng có thể tái sử dụng. Bạn hoàn toàn có thể tạo “custom pipe” của riêng mình bằng cách implement `PipeTransform` interface và trang trí nó bằng `@Pipe` decorator.
-
HttpClient là gì và các lợi ích khi sử dụng?
`HttpClient` là module client HTTP của Angular, dùng để thực hiện các yêu cầu HTTP đến backend. Nó dựa trên `Observable` của RxJS, mang lại nhiều lợi ích so với cách tiếp cận truyền thống:
- Hỗ trợ xử lý yêu cầu và phản hồi dưới dạng Observable, giúp quản lý luồng dữ liệu bất đồng bộ dễ dàng hơn.
- Tích hợp sẵn các tính năng kiểm tra lỗi mạnh mẽ.
- Hỗ trợ interceptor để chặn và sửa đổi yêu cầu/phản hồi (ví dụ: thêm token xác thực).
- Làm việc với JSON một cách tự động.
Để sử dụng, bạn cần `import { HttpClientModule } from ‘@angular/common/http’;` vào `app.module.ts` của mình.
-
Bạn thực hiện xử lý lỗi (Error Handling) trong Angular như thế nào?
Khi `HttpClient` gửi yêu cầu và gặp lỗi, nó sẽ trả về một đối tượng lỗi (thường là `HttpErrorResponse`). Chúng ta có thể bắt và xử lý lỗi này trong phương thức `subscribe()` của Observable, ở `error path`. Để xử lý lỗi một cách mạnh mẽ hơn, chúng ta thường kết hợp với toán tử `catchError` của RxJS. Nó cho phép bạn chặn lỗi, ghi log, hiển thị thông báo cho người dùng, hoặc thậm chí trả về một Observable mới để phục hồi sau lỗi.
this.httpClient.get('/api/data').pipe( catchError(error => { console.error('Đã xảy ra lỗi:', error); // Có thể trả về một Observable mới hoặc một giá trị mặc định return throwError(() => new Error('Something bad happened; please try again later.')); }) ).subscribe(data => { console.log(data); }, error => { console.error('Lỗi cuối cùng:', error); });
2.2. Tối Ưu Hiệu Suất và Quản Lý Trạng Thái
Một ứng dụng chạy nhanh, mượt mà luôn là điều mà các lập trình viên hướng tới.
-
AOT (Ahead-of-Time) là gì? Lợi ích của AOT?
AOT là quá trình biên dịch (compilation) code Angular của bạn (HTML và TypeScript) thành JavaScript thuần túy *trước khi* trình duyệt tải ứng dụng. Thay vì biên dịch trong trình duyệt (như JIT), AOT làm việc này tại build time. Điều này mang lại:
- Tăng tốc tải trang: Trình duyệt không cần biên dịch lại, chỉ cần chạy JS đã được tối ưu.
- Giảm dung lượng ứng dụng: Loại bỏ các bộ biên dịch không cần thiết.
- Tăng hiệu suất: Phát hiện lỗi template sớm, tối ưu hóa code.
- Bảo mật tốt hơn: Mã nguồn đã được biên dịch, khó reverse engineering hơn.
-
Biên dịch JIT (Just-in-Time) là gì? So sánh AOT và JIT.
Ngược lại với AOT, JIT biên dịch ứng dụng Angular trong trình duyệt, lúc runtime. Điều này có nghĩa là trình duyệt phải tải về cả bộ biên dịch của Angular, sau đó biên dịch code rồi mới chạy. JIT thường được dùng trong môi trường phát triển vì nó cho phép build nhanh và dễ debug hơn. Còn AOT là lựa chọn số một cho production build vì hiệu suất cao hơn. Về cơ bản, JIT biên dịch khi cần, còn AOT biên dịch trước.
-
Phân biệt Promise và Observable trong Angular/JavaScript.
Cả Promise và Observable đều là cách để xử lý các tác vụ bất đồng bộ, nhưng chúng khác nhau đáng kể:
- Promise: Xử lý một giá trị duy nhất trong tương lai. Nó “đẩy” giá trị hoặc lỗi một lần duy nhất rồi kết thúc. Promise không thể hủy bỏ được sau khi đã bắt đầu.
- Observable: Xử lý một “stream” các giá trị theo thời gian. Nó có thể “đẩy” nhiều giá trị, có thể đẩy lỗi, và có thể hoàn thành. Observable có thể hủy bỏ được, và là lazy (chỉ thực thi khi có người đăng ký – subscribe). Angular và RxJS tận dụng Observable rất nhiều cho các luồng dữ liệu bất đồng bộ như sự kiện, HTTP requests.
-
Multicasting trong RxJS là gì và khi nào nên sử dụng?
Multicasting là kỹ thuật để một Observable phát ra các giá trị cho nhiều người đăng ký (subscribers) cùng một lúc thông qua một đối tượng “Subject” duy nhất. Mặc định, Observable là “unicast” – mỗi người đăng ký sẽ kích hoạt một lần thực thi độc lập của Observable. Multicasting hữu ích khi bạn có một Observable tốn kém tài nguyên (ví dụ: HTTP request) và muốn chia sẻ kết quả cho nhiều thành phần mà không phải gửi lại yêu cầu nhiều lần. Các toán tử như `share`, `shareReplay`, `publish` thường được dùng để thực hiện multicasting.

2.3. Công Cụ và Kiến Trúc Nâng Cao
Một lập trình viên có kinh nghiệm sẽ biết cách tận dụng các công cụ và hiểu rõ các khái niệm kiến trúc phức tạp.
-
Codelyzer là gì? Mục đích sử dụng?
Codelyzer là một công cụ giúp chúng ta đảm bảo code Angular TypeScript tuân thủ các quy tắc mã hóa và best practices. Nó hoạt động như một bộ linter, kiểm tra code và chỉ ra các vấn đề tiềm ẩn. Tuy nhiên, cần lưu ý quan trọng là Codelyzer dựa trên TSLint, mà TSLint đã bị deprecated. Các dự án Angular hiện đại thường chuyển sang sử dụng ESLint cùng với plugin `@angular-eslint` để đạt được mục tiêu tương tự. Đây là một cập nhật quan trọng để bạn thể hiện sự hiểu biết về xu hướng công nghệ.
-
Giải thích về Service Worker trong Angular.
Service Worker là một script JavaScript chạy ngầm trong trình duyệt, độc lập với trang web. Trong Angular, Service Worker giúp ứng dụng của bạn có khả năng offline, tức là vẫn hoạt động được ngay cả khi không có kết nối internet, bằng cách lưu trữ tài nguyên (cache) và phục vụ chúng. Nó cũng hỗ trợ các tính năng PWA (Progressive Web App) như push notifications.
-
Incremental DOM và Virtual DOM có giống nhau không?
Không, chúng không giống nhau. Cả hai đều là kỹ thuật tối ưu hóa cập nhật DOM, nhưng cách tiếp cận khác biệt:
- Virtual DOM (React, Vue): Xây dựng một bản sao ảo của DOM trong bộ nhớ. Khi dữ liệu thay đổi, nó tạo ra một Virtual DOM mới, so sánh với bản cũ để tìm ra sự khác biệt, sau đó chỉ cập nhật những phần thay đổi lên DOM thật.
- Incremental DOM (Angular): Là một thư viện của Google, được thiết kế để hiệu quả hơn về mặt bộ nhớ. Thay vì xây dựng một cây DOM ảo hoàn chỉnh, Incremental DOM chỉ tạo lại các nút cần thiết và so sánh chúng tại chỗ. Nó duyệt qua cây DOM thật, so sánh trực tiếp với các node mới được tạo ra từ template, và cập nhật những phần cần thiết mà không cần một bản sao đầy đủ trong bộ nhớ.
-
Wildcard Route được dùng với mục đích gì?
Wildcard Route, thường là `path: ‘**’`, được dùng để xử lý các route không khớp. Tức là, nếu người dùng truy cập một URL mà không có route nào trong ứng dụng của bạn định nghĩa, Wildcard Route sẽ “bắt” lấy nó. Mục đích phổ biến nhất là để hiển thị một trang “404 Not Found” hoặc chuyển hướng người dùng về trang chủ. Nó phải luôn được đặt cuối cùng trong cấu hình route của bạn.
-
Component động (Dynamic Component) là gì và cách tạo.
Component động là những component không được khai báo trong template từ trước mà được tạo ra và thêm vào DOM tại runtime. Bạn sẽ cần tạo Component động khi bạn không biết trước mình sẽ cần hiển thị những component nào hoặc số lượng của chúng. Để tạo Component động, bạn thường cần sử dụng `ComponentFactoryResolver` để tạo một `ComponentFactory`, sau đó dùng `ViewContainerRef` để gắn component đó vào DOM. Đây là một kỹ thuật nâng cao, thường thấy trong các ứng dụng có cấu trúc plugin hoặc widget.
2.4. Câu Hỏi Về Kiến Trúc & Thiết Kế Ứng Dụng
Kiến thức chuyên sâu đi kèm với khả năng tư duy về cấu trúc và thiết kế.
-
Tại sao lại dùng `ngOnInit` trong khi đã có `constructor`?
`constructor` của một component/service là một hàm JavaScript/TypeScript cơ bản, được gọi *trước tiên* khi một instance của class được tạo ra. Mục đích chính của nó là để tiêm các dependencies (Dependency Injection). Còn `ngOnInit` là một lifecycle hook của Angular, được gọi *sau* `constructor` và *sau khi* Angular đã khởi tạo các input binding của component. Do đó, `ngOnInit` là nơi thích hợp để thực hiện các logic khởi tạo dữ liệu, gọi API hoặc các tác vụ phức tạp khác mà cần đến các input đã được gán giá trị.
-
Khi nào nên dùng eager loading module?
Eager loading (tải ngay lập tức) là khi các module được tải cùng lúc với module gốc của ứng dụng. Nó đối lập với lazy loading. Chúng ta nên dùng eager loading cho:
- Các module nhỏ, chứa các component/service được sử dụng thường xuyên ngay từ đầu ứng dụng.
- Các module chứa các tiện ích chung, cần thiết cho toàn bộ ứng dụng.
- Khi việc tải ngay không gây ảnh hưởng đáng kể đến hiệu suất tải trang ban đầu.
-
Làm thế nào để bảo mật code trong Angular?
Bảo mật trong Angular đòi hỏi một cách tiếp cận đa tầng:
- Cross-Site Scripting (XSS): Angular tự động sanitize (lọc bỏ) các giá trị không an toàn khi hiển thị trong template. Tuy nhiên, nếu bạn cố tình bỏ qua sanitization bằng `bypassSecurityTrust*`, hãy cẩn thận.
- Cross-Site Request Forgery (CSRF): Đảm bảo backend của bạn sử dụng các token CSRF để xác thực yêu cầu.
- Kiểm soát truy cập: Sử dụng các Guards trong Router để kiểm tra quyền của người dùng trước khi cho phép truy cập một route nào đó.
- Input sanitization & Validation: Luôn kiểm tra và làm sạch dữ liệu đầu vào cả ở frontend và backend.
- Authentication & Authorization: Triển khai các cơ chế xác thực người dùng (JWT, OAuth) và phân quyền hợp lý.
- Cập nhật phiên bản Angular: Luôn dùng phiên bản Angular mới nhất để hưởng lợi từ các bản vá bảo mật.

Luồng dữ liệu động và hiệu quả trong mạng lưới nút phức tạp, minh họa khả năng xử lý nhạy bén, liên quan đến các câu hỏi phỏng vấn Angular Developer về hiệu suất hệ thống. -
Reactive Programming là gì? Có liên quan đến Angular không?
Lập trình phản ứng (Reactive Programming) là một mô hình lập trình tập trung vào các luồng dữ liệu (data streams) và sự truyền bá của thay đổi (propagation of change). Nó cho phép chúng ta xử lý các tác vụ bất đồng bộ và sự kiện một cách dễ dàng hơn, minh bạch hơn. Trong Angular, Reactive Programming gắn liền mật thiết với RxJS (Reactive Extensions for JavaScript). RxJS cung cấp các `Observable` và một bộ sưu tập phong phú các toán tử để tạo, biến đổi và tiêu thụ các luồng dữ liệu. Angular sử dụng RxJS cho `HttpClient`, Router, và nhiều API khác, biến RxJS trở thành một phần không thể thiếu của việc phát triển ứng dụng Angular hiện đại.
3. Kỹ Năng Giải Quyết Vấn Đề và Tư Duy Lập Trình (Technical Skill Questions)
Kiến thức nền tảng là một chuyện, nhưng khả năng áp dụng kiến thức đó vào giải quyết vấn đề thực tế lại là một đẳng cấp khác. Phần này sẽ kiểm tra tư duy và kỹ năng thực hành của bạn.
3.1. Viết Code và Thực Hành
Đôi khi, nhà tuyển dụng sẽ yêu cầu bạn viết một đoạn code hoặc giải thích cách bạn làm một tác vụ cụ thể.
-
Viết chương trình khởi động cơ bản trong Angular (Modern Angular).
Một ứng dụng Angular hiện đại thường bắt đầu từ `main.ts`, bootstrap `AppModule`. `AppModule` sau đó khai báo `AppComponent` là component gốc. Đây là một cấu trúc cơ bản:
- `main.ts` (điểm khởi đầu):
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; platformBrowserDynamic().bootstrapModule(AppModule) .catch(err => console.error(err)); - `app/app.module.ts`:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent] // Component gốc được bootstrap
})
export class AppModule { }
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: '<h1>Chào mừng đến với Angular!</h1>',
styles: ['h1 { color: blue; }']
})
export class AppComponent {
title = 'my-angular-app';
}
Angular CLI là một công cụ thần thánh giúp chúng ta làm việc với Angular cực kỳ hiệu quả.
- Khởi tạo một dự án Angular mới: `ng new my-app`
- Chạy một dự án Angular trên môi trường dev: `ng serve`
- Tạo component: `ng generate component my-component` (hoặc `ng g c my-component`)
- Tạo service: `ng generate service my-service` (hoặc `ng g s my-service`)
- Tạo module: `ng generate module my-module` (hoặc `ng g m my-module`)
Angular cung cấp hai cách chính để làm việc với form:
- Template-driven forms: Dễ sử dụng cho các form đơn giản. Logic form chủ yếu nằm trong template HTML, dùng các directive như `ngModel`, `ngForm`. Nó phù hợp cho các form ít phức tạp, validation đơn giản.
- Reactive forms: Mạnh mẽ và linh hoạt hơn, phù hợp cho các form phức tạp, validation động, và khi bạn cần kiểm soát nhiều hơn về trạng thái của form. Logic form được định nghĩa hoàn toàn trong component TypeScript, dùng các class như `FormControl`, `FormGroup`, `FormArray`.

Tùy vào độ phức tạp của form mà chúng ta chọn cách tiếp cận phù hợp. Với các ứng dụng lớn, Reactive forms thường là lựa chọn ưu tiên vì khả năng testability và khả năng mở rộng.
Angular CLI tích hợp sẵn Karma (test runner) và Jasmine (framework test) để chạy unit test. Bạn chỉ cần dùng lệnh `ng test`. Các file test (thường có đuôi `.spec.ts`) sẽ được tìm thấy và chạy. Bạn có thể viết các `describe` block để nhóm các test case và dùng `it` block để định nghĩa từng test cụ thể, sử dụng `expect` để kiểm tra kết quả.
Để theo dõi sự thay đổi của route, bạn có thể inject `Router` service và đăng ký (subscribe) vào `Router.events`. Observable này sẽ phát ra các sự kiện khác nhau trong quá trình điều hướng (như `NavigationStart`, `NavigationEnd`, `RoutesRecognized`, v.v.). Bạn có thể lọc các sự kiện này để chỉ lắng nghe những gì bạn quan tâm.
constructor(private router: Router) {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
console.log('Điều hướng hoàn tất đến:', event.urlAfterRedirects);
});
}
3.2. Xử Lý Tình Huống Thực Tế
Đây là lúc bạn kể về những trải nghiệm của mình, cách bạn đối mặt với khó khăn.
-
Bạn đã từng gặp phải lỗi dự án khiến ảnh hưởng đến các bên liên quan chưa? Trong trường hợp ấy bạn xử lý thế nào?
Chắc chắn rồi, ai làm nghề này mà chẳng gặp lỗi. Quan trọng là cách mình ứng phó. Tôi thường bắt đầu bằng việc bình tĩnh đánh giá mức độ ảnh hưởng của lỗi. Sau đó, tôi nhanh chóng tìm ra nguyên nhân gốc rễ (root cause) bằng cách debug, xem log, và tái hiện lỗi. Bước tiếp theo là đưa ra giải pháp khắc phục tạm thời để giảm thiểu thiệt hại, sau đó mới là giải pháp lâu dài. Song song đó, việc giao tiếp rõ ràng, kịp thời với các bên liên quan (quản lý, khách hàng, các team khác) là cực kỳ quan trọng để họ nắm được tình hình và không cảm thấy bị bỏ rơi. Từ những lỗi như vậy, tôi luôn rút ra bài học để cải thiện quy trình làm việc và kiểm thử.
-
Bạn có thể kể về dự án phát triển web phức tạp mà bạn đã tham gia được chứ?
Hãy chọn một dự án mà bạn thực sự tự hào hoặc đã học được nhiều điều. Mô tả rõ vai trò của bạn, những công nghệ bạn đã sử dụng (đặc biệt là Angular và các thư viện liên quan như RxJS, NgRx nếu có). Kể về những thách thức kỹ thuật mà bạn gặp phải (ví dụ: tối ưu hiệu suất với dữ liệu lớn, xử lý đồng bộ/bất đồng bộ phức tạp, tích hợp với hệ thống legacy) và cách bạn cùng team đã vượt qua chúng. Nhấn mạnh vào những đóng góp cá nhân của bạn và kết quả đạt được.
-
Kinh nghiệm sử dụng local storage để thay thế cookie?
Cả `localStorage` và `cookie` đều là cơ chế lưu trữ dữ liệu phía client, nhưng chúng có những ưu nhược điểm riêng. `localStorage` có dung lượng lớn hơn nhiều (thường là 5-10MB) và không tự động gửi về server trong mỗi request, phù hợp để lưu trữ dữ liệu không nhạy cảm như cài đặt người dùng, trạng thái UI. `cookie` thì dung lượng nhỏ hơn (khoảng 4KB), tự động gửi về server, thường dùng để lưu trữ session ID hoặc token xác thực. Tôi thường dùng `localStorage` để lưu trữ thông tin đăng nhập (token JWT) hoặc các tùy chọn của người dùng để giảm tải cho network và tăng tốc độ tải trang.
4. Chuẩn Bị Toàn Diện Cho Buổi Phỏng Vấn Angular
Một buổi phỏng vấn thành công không chỉ đến từ kiến thức chuyên môn, mà còn là sự chuẩn bị kỹ lưỡng về mọi mặt.
4.1. Chuẩn Bị Kiến Thức Chuyên Môn
- Ôn tập lại các khái niệm cơ bản và nâng cao. Đừng chủ quan với những thứ tưởng chừng đơn giản nhất. Nhiều khi, những cái nhỏ lại là thứ định hình sự khác biệt.
- Cập nhật các phiên bản Angular và xu hướng công nghệ mới nhất. Angular không ngừng phát triển. Hãy xem những tính năng mới trong các phiên bản gần đây, ví dụ như Standalone Components, để chứng tỏ bạn là người luôn học hỏi.
- Thực hành viết code và giải quyết các bài toán thuật toán nhỏ liên quan đến JavaScript/TypeScript. Nhiều buổi phỏng vấn sẽ có phần coding challenge trực tiếp hoặc trên nền tảng. Luyện tập thường xuyên sẽ giúp bạn phản xạ nhanh hơn.
4.2. Kỹ Năng Mềm & Tư Duy
- Tìm hiểu kỹ về công ty tuyển dụng và vị trí công việc. Văn hóa công ty họ thế nào? Sản phẩm chính là gì? Vị trí bạn ứng tuyển yêu cầu những gì? Điều này giúp bạn thể hiện sự nhiệt tình và phù hợp.
- Luyện tập trả lời phỏng vấn: Hãy tập nói to, rành mạch. Nhờ bạn bè hoặc mentor phỏng vấn thử, hoặc tự quay video lại để xem mình thể hiện thế nào. Đặc biệt là các câu hỏi tình huống, cách bạn xử lý xung đột trong môi trường làm việc.
- Chuẩn bị câu hỏi thông minh để hỏi nhà tuyển dụng. Đây là cơ hội để bạn thể hiện sự quan tâm thực sự đến công việc và công ty. Hãy hỏi về lộ trình phát triển, về đội nhóm, về công nghệ họ đang dùng, hay thách thức của dự án.
- Rèn luyện kỹ năng giao tiếp, EQ và AQ. Dù là dân kỹ thuật, giao tiếp tốt vẫn là chìa khóa. Khả năng lắng nghe, đặt câu hỏi, và kiểm soát cảm xúc khi đối mặt với áp lực là rất quan trọng.
4.3. Các Yếu Tố Khác
- Chuẩn bị sẵn sàng cho các bài thực hành lập trình trực tiếp (coding challenge). Luôn có một môi trường code thoải mái, có thể là IDE quen thuộc của bạn.
- Mang theo sổ tay và bút để ghi chú. Đây là cách thể hiện sự chuyên nghiệp và giúp bạn ghi nhớ những thông tin quan trọng mà nhà tuyển dụng chia sẻ.
- Giữ thái độ tự tin, thoải mái và chuyên nghiệp. Một nụ cười thân thiện, ánh mắt giao tiếp và sự tự tin sẽ tạo ấn tượng tốt ngay từ đầu.
5. Bí Quyết Tìm Kiếm Việc Làm Angular Thu Nhập Hấp Dẫn
Sau khi đã mài sắc kiến thức và kỹ năng phỏng vấn, bước tiếp theo là đưa mình ra thị trường để tìm kiếm cơ hội phù hợp.
5.1. Tận Dụng Mạng Lưới Cá Nhân
- Tham gia các cộng đồng IT, Angular Developer online/offline. Đây là nơi tuyệt vời để học hỏi, chia sẻ và kết nối. Rất nhiều cơ hội việc làm tốt đến từ network cá nhân.
- Kết nối với những người quen trong ngành để được giới thiệu. Lời giới thiệu từ người có uy tín thường sẽ được các nhà tuyển dụng ưu tiên hơn.
5.2. Các Kênh Tìm Việc Chuyên Nghiệp
- Tìm kiếm trên các nền tảng tuyển dụng chuyên về IT uy tín. Có rất nhiều nền tảng cung cấp việc làm Angular được cập nhật liên tục từ các công ty công nghệ hàng đầu, từ startup đến tập đoàn lớn.
- Theo dõi website tuyển dụng của các công ty bạn mong muốn làm việc. Nếu bạn có một danh sách “công ty mơ ước”, hãy chủ động kiểm tra trang sự nghiệp của họ.
Tổng kết lại, con đường chinh phục sự nghiệp Angular không hề dễ dàng nhưng cũng đầy hứa hẹn. Việc chuẩn bị kỹ lưỡng từ kiến thức chuyên môn, kỹ năng mềm đến khả năng giải quyết vấn đề là chìa khóa để bạn tự tin vượt qua mọi buổi phỏng vấn. Hãy luôn giữ tinh thần học hỏi, cập nhật kiến thức mới nhất, và biến mỗi thất bại thành một bài học giá trị. Tôi tin rằng với sự chuẩn bị chu đáo và niềm đam mê, bạn sẽ sớm tìm được vị trí mơ ước và gặt hái thành công. Nếu có bất kỳ thắc mắc nào, đừng ngần ngại để lại bình luận nhé! Chúc bạn may mắn trên hành trình này!