Angular khác React ở điểm nào là cốt lõi nhất khi chọn công nghệ cho dự án?
A.React có TypeScript còn Angular chỉ viết được bằng JavaScript thuần
B.Angular chạy trên server còn React chạy trên trình duyệt, nên hai bên không cùng bài toán
C.Angular là framework trọn gói; React là thư viện view, phần còn lại team tự chọn
D.Angular không dùng component, chỉ dùng template HTML rời như jQuery
Đáp án: C
Angular là framework trọn gói: router, HTTP client, forms, dependency injection, CLI và testing đều do đội Angular cung cấp và version cùng nhau. React là thư viện view — router, state management, form phải chọn thêm từ hệ sinh thái. Đổi lại, Angular ràng buộc kiến trúc chặt hơn, React linh hoạt hơn nhưng team phải tự quyết nhiều thứ.
B.Một object literal export mặc định, trong đó thuộc tính render là bắt buộc phải có
C.Chỉ một file HTML — Angular tự sinh class tương ứng lúc build
D.Một hàm trả về JSX giống React, được đăng ký qua NgModule
Đáp án: A
Component Angular gồm ba phần: class TypeScript giữ state và logic, template HTML mô tả giao diện, và style. Decorator @Component nối chúng lại qua metadata: selector (tên thẻ dùng trong template khác), template/templateUrl và styles/styleUrl. Angular đọc metadata này lúc biên dịch để sinh code render.
Phát biểu nào sau đây SAI về standalone component?
A.Bỏ được lớp trung gian NgModule nên ít file khai báo lặp và ít lỗi vặt
B.Lazy load thẳng một component bằng loadComponent, không cần bọc module
C.Component tự khai báo phụ thuộc qua mảng imports, không cần declarations
D.Loại bỏ hoàn toàn dependency injection — service không cần provider nữa
Đáp án: D
Standalone component tự khai báo phụ thuộc trong imports của chính nó, nên không cần NgModule để declarations/exports. Kết quả: ít file trung gian, phụ thuộc nằm cạnh nơi dùng, lazy load thẳng bằng loadComponent. Dependency injection không đổi — service vẫn dùng providedIn: "root" hoặc provider theo route.
Trong template dưới đây, ba dòng dùng ba cơ chế binding khác nhau. Mô tả nào đúng?
html
<h2>{{ title }}</h2><img [src]="avatarUrl" [alt]="userName"><button (click)="save()">Lưu</button>
A.Cả ba đều là two-way binding, dữ liệu tự đồng bộ hai chiều
B.[src] gán vào HTML attribute, còn {{ }} gán vào property — hai cái tương đương nhau
C.(click)="save()" chỉ chạy được nếu save được khai báo trong template chứ không phải trong class
D.Interpolation đưa giá trị vào text; [prop] gán property; (event) nghe sự kiện
Đáp án: D
Interpolation {{ expr }} chèn giá trị vào nội dung text. Property binding [prop]="expr" gán vào property của DOM element hoặc input của component, chiều component → template. Event binding (event)="handler()" chạy phương thức của class khi sự kiện xảy ra, chiều template → component. Muốn gán HTML attribute thật thì dùng [attr.aria-label].
@Input() và @Output() dùng để làm gì trong giao tiếp giữa component cha và con?
A.@Input() nhận dữ liệu từ cha; @Output() phát sự kiện lên cha
B.Cả hai đều truyền dữ liệu hai chiều, nên sửa ở con là cha tự đổi theo
C.@Input() dành cho service, @Output() dành cho HTTP response
D.@Output() truyền dữ liệu từ cha xuống con, còn @Input() gửi ngược lên
Đáp án: A
@Input() khai báo property mà component cha gán vào bằng property binding (<child [value]="x">) — dữ liệu đi từ cha xuống con. @Output() khai báo một EventEmitter, con gọi emit(payload) và cha lắng nghe bằng (changed)="onChanged($event)" — sự kiện đi từ con lên cha. Luồng dữ liệu vì thế luôn rõ một chiều mỗi hướng.
Structural directive khác attribute directive ở điểm nào?
A.Structural directive không được tự viết, chỉ Angular mới định nghĩa được
B.Structural directive thêm/bớt phần tử khỏi DOM; attribute chỉ đổi diện mạo
C.Attribute directive bắt buộc phải có dấu * phía trước tên
D.Structural directive chỉ chạy trên server, attribute directive chỉ chạy trên client
Đáp án: B
Structural directive thay đổi cấu trúc DOM: thêm, bớt hoặc lặp phần tử — *ngIf, *ngFor, *ngSwitchCase. Dấu * là cú pháp rút gọn của việc bọc phần tử trong <ng-template>. Attribute directive giữ nguyên cấu trúc và chỉ thay đổi diện mạo hay hành vi của phần tử sẵn có — ngClass, ngStyle, hoặc directive tự viết.
const count = signal(0)
console.log(count()) // 0 — đọc bằng cách gọi hàm
count.set(5)
count.update(n => n + 1)
A.Một cơ chế gửi sự kiện giữa các component, thay thế cho @Output()
B.Một decorator đánh dấu property cần được change detection theo dõi
C.Wrapper quanh giá trị, đọc bằng cách gọi như hàm; Angular ghi nhận nơi đọc nó
D.Một Observable của RxJS được đổi tên, có đầy đủ operator như map, filter, switchMap
Đáp án: C
Signal là một ô chứa giá trị có khả năng thông báo khi giá trị đó thay đổi. Đọc bằng cách gọi như hàm — count() — và mỗi lần đọc trong ngữ cảnh phản ứng (template, computed, effect) sẽ đăng ký một phụ thuộc. Ghi bằng set() hoặc update(). Nhờ biết chính xác nơi nào phụ thuộc, Angular chỉ cập nhật đúng phần đó thay vì kiểm tra cả cây component.
Dependency Injection trong Angular hoạt động theo nguyên tắc nào?
A.Class khai báo thứ nó cần, Angular tra injector và tự cung cấp instance
B.Service chỉ dùng được trong component đã import file service đó bằng import của ES module
C.Mỗi class tự new service của nó để đảm bảo không dùng chung state
D.Angular tự động import service dựa trên tên file, không cần khai báo gì
Đáp án: A
DI đảo ngược quyền tạo phụ thuộc: class chỉ khai báo mình cần gì, còn việc tạo và cung cấp instance do injector của Angular lo. Service đánh dấu @Injectable({ providedIn: "root" }) là có sẵn toàn ứng dụng dưới dạng singleton. Nhờ vậy khi test có thể cung cấp bản thay thế mà không sửa code component.
B.Route phải khai báo trong NgModule, standalone app không dùng router được
C.<router-outlet> chỉ dùng cho lazy route, route thường render thẳng vào body
D.Chỉ cần đặt file component vào thư mục theo tên đường dẫn, Angular tự sinh route
Đáp án: A
Ba mảnh: mảng Routes ánh xạ path sang component (kèm :id cho tham số động và ** cho trang không khớp), đăng ký bằng provideRouter(routes) trong bootstrapApplication, và <router-outlet> đánh dấu nơi component của route được render. Điều hướng trong template dùng routerLink, trong code dùng Router.navigate().
B.Biến đổi giá trị ngay trong template khi hiển thị
C.Nối nhiều Observable lại với nhau
D.Truyền dữ liệu từ component cha xuống component con
Đáp án: B
Pipe biến đổi giá trị hiển thị ngay trong template: {{ date | date:"dd/MM/yyyy" }}. Angular có sẵn date, currency, number, json, async. Điểm cần nắm: pipe mặc định là pure — chỉ chạy lại khi tham chiếu đầu vào đổi, nên rất rẻ.
Trong ứng dụng Angular hiện đại dùng standalone component, NgModule còn vai trò gì?
A.Không còn tồn tại trong Angular hiện đại — code có NgModule sẽ không biên dịch được
B.Vẫn bắt buộc phải có ít nhất một NgModule gốc thì mới bootstrap được ứng dụng
C.Chủ yếu để tương thích với thư viện cũ và gom provider khi migrate dần
D.Chỉ còn dùng cho lazy loading, vì loadComponent không tồn tại
Đáp án: C
NgModule vẫn được hỗ trợ nhưng không còn là mặc định. Vai trò còn lại: tương thích với thư viện cũ xuất NgModule, và làm nơi gom một nhóm provider hoặc khai báo dùng chung trong quá trình migrate dần. Ứng dụng mới bootstrap bằng bootstrapApplication(AppComponent, { providers: [...] }), và mỗi standalone component tự khai báo imports của mình.
Lifecycle hook nào là nơi đúng để đọc giá trị @Input() lần đầu và vì sao không đặt ở constructor?
A.ngAfterViewInit — vì input thuộc về view nên phải chờ view khởi tạo xong
B.ngOnDestroy — vì đó là hook chạy sau cùng nên chắc chắn input đã có giá trị
C.ngOnInit — constructor chạy trước khi Angular gán giá trị input
D.Constructor — Angular gán input trước khi gọi constructor
Đáp án: C
Dùng ngOnInit. Thứ tự là: constructor → gán input → ngOnChanges → ngOnInit → ngAfterViewInit → ... → ngOnDestroy. Constructor chạy lúc instance vừa tạo nên input còn undefined; vì vậy constructor chỉ nên nhận dependency, còn khởi tạo dựa trên input đặt ở ngOnInit. Muốn phản ứng mỗi lần input đổi thì dùng ngOnChanges hoặc signal input kèm computed/effect.
A.Signal input chỉ dùng được trong component không standalone
B.Giá trị được bọc trong signal nên computed/effect phản ứng trực tiếp
C.Signal input cho phép component con gán giá trị ngược lên cha bằng set()
D.Chỉ là cú pháp ngắn hơn, bên trong Angular vẫn gọi ngOnChanges nên phải tự so sánh giá trị
Đáp án: B
input() trả về một signal chỉ đọc: đọc bằng user() và mọi computed/effect đọc nó sẽ tự chạy lại khi cha truyền giá trị mới. input.required<T>() bắt buộc cha phải truyền, compiler báo lỗi nếu thiếu. So với @Input(), không cần ngOnChanges để theo dõi thay đổi, và kiểu dữ liệu chặt hơn vì không phải khai báo undefined cho trạng thái chưa gán.
A.@for không cần khoá định danh vì Angular tự so sánh bằng tham chiếu
B.@if chỉ hoạt động với signal, không dùng được với biến thường
C.Tích hợp trong compiler nên không cần CommonModule; track là bắt buộc
D.Chỉ là đổi cú pháp cho đẹp, bản chất vẫn được biên dịch thành *ngIf/*ngFor
Đáp án: C
Control flow mới nằm trong compiler chứ không phải directive, nên template không cần import CommonModule. Cú pháp đầy đủ hơn: @else if/@else, @empty cho danh sách rỗng, và as để đặt tên giá trị. track trong @for là bắt buộc — buộc phải nghĩ về khoá định danh, thứ quyết định hiệu năng khi danh sách thay đổi.
Vì sao biểu thức track trong @for lại quan trọng với hiệu năng?
A.Nó sắp xếp danh sách theo giá trị track trước khi render ra DOM
B.Nó lọc bỏ các item trùng lặp trong mảng
C.Cho Angular biết "vẫn là item đó" giữa hai lần render
D.Nó cache dữ liệu vào localStorage giữa các lần điều hướng trang
Đáp án: C
track cung cấp danh tính ổn định cho mỗi item. Khi mảng thay đổi, Angular so khớp theo giá trị track để biết node DOM nào giữ lại, node nào thêm hay xoá. Không có danh tính đúng, mọi item được coi là mới và cả danh sách bị dựng lại — mất state của component con, mất focus, và mất hiệu năng. Dùng id ổn định từ dữ liệu; chỉ dùng chỉ số khi danh sách thuần tĩnh.
A.Tách phần template kèm phụ thuộc ra khỏi bundle ban đầu, chỉ tải khi cần
B.Thay thế cho lazy loading route — dùng @defer thì không cần chia route nữa
C.@defer chỉ kích hoạt được thủ công bằng cách gọi hàm trong class
D.Khối @defer vẫn nằm trong bundle ban đầu, chỉ hoãn việc render ra DOM
Đáp án: A
@defer chia một phần template và phụ thuộc của nó thành chunk riêng, chỉ tải khi trigger xảy ra: on idle (mặc định), on viewport, on interaction, on hover, on timer, hoặc when <điều kiện>. Đi kèm là @placeholder (hiện trước khi tải), @loading (trong lúc tải) và @error. Dùng cho khối nặng và không quan trọng ngay: biểu đồ, editor, phần bình luận.
A.Khi muốn component con tự gọi API mà không cần cha biết
B.Khi cần truyền dữ liệu bất đồng bộ từ service xuống component con
C.Khi component là khung chứa và nội dung do phía gọi quyết định
D.Chỉ dùng được một <ng-content> duy nhất cho mỗi component, không thể chia nhiều vùng
Đáp án: C
<ng-content> dùng khi component là khung chứa (card, modal, panel) và nội dung bên trong do nơi gọi quyết định. Cha viết markup bên trong thẻ component, Angular chiếu markup đó vào vị trí <ng-content>. Nhiều vùng thì dùng select với CSS selector: <ng-content select="[card-title]">. Truyền markup dùng projection; truyền dữ liệu dùng input.
A.Cả ba đều ghi được, chỉ khác nhau ở cú pháp khai báo
B.computed chạy lại mỗi lần change detection chạy, bất kể phụ thuộc có đổi hay không
C.signal giữ state ghi được; computed dẫn xuất có cache; effect tác dụng phụ
D.effect là nơi nên tính giá trị dẫn xuất rồi set ngược vào signal khác
Đáp án: C
signal(v) giữ state ghi được, đổi bằng set/update. computed(fn) khai báo giá trị dẫn xuất: chỉ tính khi có người đọc, cache kết quả và tính lại khi phụ thuộc đổi. effect(fn) dành cho tác dụng phụ — ghi log, đồng bộ localStorage, gọi API bên ngoài hệ thống signal. Giá trị dẫn xuất luôn nên là computed, không phải effect ghi ngược vào signal khác.
Khi nào nên dùng Signal và khi nào nên giữ Observable trong Angular?
A.Signal chỉ dùng được trong template, không dùng được trong service
B.Observable đồng bộ còn Signal bất đồng bộ
C.Signal thay thế hoàn toàn RxJS; codebase hiện đại không nên còn Observable nào
D.Signal cho state đồng bộ UI đọc; Observable cho luồng sự kiện theo thời gian
Đáp án: D
Signal biểu diễn state: luôn có giá trị hiện tại, đọc đồng bộ, hợp với thứ mà template cần hiển thị. Observable biểu diễn luồng sự kiện theo thời gian: HTTP, gõ phím có debounce, WebSocket, các luồng cần huỷ hoặc thử lại. Hai bên chuyển đổi qua lại bằng toSignal() và toObservable(), nên thực tế thường dùng Observable ở tầng dữ liệu và signal ở tầng hiển thị.
Với ChangeDetectionStrategy.OnPush, trường hợp nào KHÔNG khiến component được kiểm tra lại?
A.Signal được đọc trong template thay đổi giá trị, hoặc async pipe nhận giá trị mới
B.Sự kiện DOM phát ra từ chính template của component (ví dụ (click))
C.Một @Input() nhận tham chiếu mới (so sánh bằng ===)
D.Mutate một thuộc tính bên trong object đã truyền qua input mà không tạo object mới
Đáp án: D
OnPush khiến Angular chỉ kiểm tra component khi: input nhận tham chiếu mới, sự kiện phát ra từ template của component, signal đọc trong template đổi giá trị, hoặc async pipe phát giá trị mới. Sửa trực tiếp bên trong object đã truyền vào (giữ nguyên tham chiếu) sẽ không kích hoạt kiểm tra — đó là lý do OnPush đi kèm với dữ liệu bất biến.
A.Biến Observable thành Promise rồi await trong template
B.Chỉ để rút gọn cú pháp, vẫn phải gọi unsubscribe trong ngOnDestroy
C.Cache kết quả HTTP để lần điều hướng sau không gọi lại API
D.Tự subscribe khi view khởi tạo và tự unsubscribe khi view bị huỷ
Đáp án: D
async pipe subscribe hộ và huỷ subscription khi view bị destroy, nên không cần dọn dẹp thủ công. Mỗi giá trị mới, pipe đánh dấu component cần kiểm tra lại nên hoạt động đúng cả với OnPush. Lưu ý dùng một lần và gán bằng as — mỗi chỗ | async là một subscription riêng, với cold observable như HTTP sẽ thành nhiều lần gọi API.
Khai báo service bằng providedIn: "root" khác với đặt vào providers của một component thế nào?
A.providedIn: "root" cho instance dùng chung; providers tạo instance riêng
B.Đặt trong providers của component thì service không inject được service khác
C.providedIn: "root" tạo instance mới cho mỗi component inject nó
D.Hai cách hoàn toàn tương đương, chỉ khác chỗ viết
Đáp án: A
providedIn: "root" đăng ký service ở injector gốc: một instance duy nhất cho cả ứng dụng, sống đến khi ứng dụng đóng, và bị loại khỏi bundle nếu không ai inject. Đưa service vào providers của một component tạo instance riêng cho mỗi instance component, huỷ khi component bị destroy — hợp với state cục bộ của một màn hình, không hợp với dữ liệu cần chia sẻ.
A.inject() chỉ dùng được cho service của Angular, không dùng được cho service tự viết
B.inject() chỉ gọi được trong ngữ cảnh injection, bù lại dùng được trong hàm
C.inject() tạo instance mới mỗi lần gọi, khác với constructor injection dùng singleton
D.inject() gọi được ở bất kỳ đâu, kể cả trong callback của setTimeout
Đáp án: B
Hai cách cùng tra một injector và nhận cùng instance. Khác biệt là nơi gọi: inject() chỉ hợp lệ trong ngữ cảnh injection — khởi tạo field, constructor, hoặc factory — nhưng nhờ là hàm nên dùng được trong functional guard, interceptor và các hàm tiện ích dùng chung. Code cũng gọn hơn khi kế thừa vì không phải chuyển tiếp tham số constructor của lớp cha.
A.Đặt thuộc tính lazy: true trong định nghĩa route
B.loadComponent với dynamic import; cả nhánh route thì loadChildren
C.Angular tự lazy load mọi route mà không cần cấu hình
D.Phải tạo một NgModule riêng cho mỗi trang rồi dùng loadChildren trỏ tới nó
Đáp án: B
Dùng loadComponent: () => import("./page").then(m => m.PageComponent) cho một trang standalone — bundler tách chunk riêng, chỉ tải khi vào route. Muốn lazy cả một nhánh thì loadChildren: () => import("./feature.routes").then(m => m.routes). Route khai báo component trực tiếp luôn nằm trong bundle ban đầu.
Reactive Forms và Template-driven Forms nên chọn cái nào cho form phức tạp, vì sao?
A.Reactive Forms — cấu trúc form định nghĩa trong class nên kiểm thử được
B.Phải dùng cả hai cùng lúc trong cùng một form để tận dụng ưu điểm của mỗi bên
C.Cả hai như nhau về khả năng, chỉ khác nơi khai báo
D.Template-driven — vì viết ít code hơn nên luôn là lựa chọn tốt hơn
Đáp án: A
Form phức tạp nên dùng Reactive Forms: cấu trúc khai báo trong class (FormGroup, FormControl, FormArray), nên viết unit test không cần render, thêm/bớt control lúc chạy dễ, và validator là hàm thuần. Template-driven (ngModel) hợp với form nhỏ vài trường; nó dựng control ngầm trong template và cập nhật bất đồng bộ, nên logic phức tạp sẽ khó kiểm soát.
viewChild() (signal query) khác @ViewChild truyền thống ở điểm nào?
A.Nó chỉ dùng được với component chứ không với directive
B.Nó trả về signal nên đọc được ở mọi lúc, không phải chờ hook
C.Nó tìm được cả element nằm trong content projection
D.Nó chạy lại truy vấn ở mỗi chu kỳ change detection
Đáp án: B
Nó trả về một tín hiệu nên đọc được ở mọi lúc bằng cách gọi nó. Cách cũ buộc phải đọc trong hook vòng đời sau khi view khởi tạo — đọc sớm hơn thì giá trị còn rỗng, một lỗi rất hay gặp.
B.Render một ng-template được truyền vào, kèm context tuỳ chọn
C.Định nghĩa một template dùng chung cho nhiều component
D.Chèn HTML thô từ một chuỗi vào template
Đáp án: B
Render một template được truyền vào, kèm một đối tượng ngữ cảnh tuỳ chọn. Nhờ đó một thành phần bảng cho nơi sử dụng tự quyết định cách vẽ từng ô, trong khi bản thân bảng vẫn giữ logic phân trang và sắp xếp.
Thuộc tính host trong decorator component dùng để làm gì?
A.Khai báo component được phép nhúng vào những trang nào
B.Gắn class, attribute và event listener lên chính element của component
C.Chọn element gốc sẽ được tạo cho component
D.Cấu hình cách component giao tiếp với component cha
Đáp án: B
Gắn lớp CSS, thuộc tính và listener sự kiện lên chính phần tử của thành phần. Nhờ đó không cần một thẻ bọc thừa chỉ để đặt lớp hay bắt sự kiện — cây DOM sạch hơn.
CSS của một component Angular mặc định không ảnh hưởng component khác. Vì sao?
A.CSS được nạp trong một iframe riêng cho mỗi component
B.Angular đổi tên các class thành chuỗi băm ngẫu nhiên
C.Mỗi component được render trong một shadow DOM riêng
D.Angular thêm attribute duy nhất vào element và selector
Đáp án: D
Framework thêm một thuộc tính duy nhất vào các phần tử của thành phần và vào bộ chọn CSS tương ứng. Đây là cách giả lập cô lập kiểu mà không cần dùng shadow DOM thật, nên tương thích rộng hơn.
A.Một signal hai chiều: vừa là input vừa tự phát output tương ứng
B.Một signal chỉ đọc dùng để phơi state ra ngoài component
C.Một form control liên kết với template-driven form
D.Một lớp mô hình dữ liệu để định nghĩa cấu trúc entity
Đáp án: A
Một tín hiệu hai chiều: vừa nhận giá trị từ thành phần cha như đầu vào, vừa tự phát sự kiện tương ứng khi bị ghi. Bên sử dụng dùng cú pháp liên kết hai chiều, không phải tự viết cặp đầu vào và đầu ra.
Khối @defer được kích hoạt bằng những trigger nào?
A.Chỉ khi route chứa nó được kích hoạt
B.Chỉ khi người dùng bấm vào một phần tử được chỉ định
C.Chỉ khi một biểu thức trong component trả về đúng
D.Khi vào viewport, khi tương tác, khi hover, khi rảnh, hoặc theo timer
Đáp án: D
Nhiều điều kiện: khi khối lọt vào vùng nhìn thấy, khi người dùng tương tác hoặc rê chuột, khi trình duyệt rảnh, sau một khoảng thời gian, hoặc theo một biểu thức tự viết. Ghép nhiều điều kiện cùng lúc được.
A.Khi đọc một signal mà không muốn effect chạy lại vì nó
B.Khi effect được khai bên ngoài injection context
C.Khi effect cần chạy đồng bộ thay vì theo lịch
D.Khi cần ghi vào một signal từ trong effect
Đáp án: A
Khi cần đọc giá trị của một tín hiệu mà không muốn hiệu ứng chạy lại vì nó thay đổi. Không có nó, mọi tín hiệu được đọc trong hiệu ứng đều trở thành phụ thuộc và hiệu ứng chạy lại nhiều hơn cần thiết.
B.Cái đầu dùng với chiến lược mặc định, cái sau với OnPush
C.Cái đầu chỉ kiểm component hiện tại, cái sau kiểm toàn ứng dụng
D.Cái đầu đánh dấu để kiểm ở chu kỳ sau; cái sau chạy kiểm ngay lập tức
Đáp án: D
Cái đầu đánh dấu thành phần và các cha của nó là cần kiểm ở chu kỳ tiếp theo. Cái sau chạy kiểm ngay lập tức trên cây con hiện tại. Cái đầu là lựa chọn mặc định vì nó để framework gom các thay đổi lại.
Component OnPush nhận @Input() items: Item[]. Push thêm phần tử vào mảng thì sao?
A.UI cập nhật nhưng chậm một chu kỳ
B.Angular ném lỗi vì input bị sửa từ bên ngoài
C.UI cập nhật bình thường vì Angular theo dõi nội dung mảng
D.UI không cập nhật vì tham chiếu mảng không đổi
Đáp án: D
Giao diện không cập nhật. Chiến lược này so sánh tham chiếu của đầu vào, mà sửa mảng tại chỗ giữ nguyên tham chiếu. Cách sửa là tạo mảng mới thay vì sửa tại chỗ.
C.Làm khoá DI cho giá trị không phải class: config, hằng số, interface
D.Xác thực người dùng trước khi cho phép inject một service
Đáp án: C
Làm khoá tiêm phụ thuộc cho những thứ không phải lớp: đối tượng cấu hình, hằng số, hoặc một interface. Interface bị xoá khi biên dịch nên không làm khoá được, còn dùng chuỗi thì dễ trùng tên giữa các thư viện.
useClass, useValue, useFactory, useExisting khác nhau thế nào?
A.Theo phạm vi sống của giá trị được tạo ra
B.Theo thứ tự ưu tiên khi có nhiều provider cùng token
C.Theo cách tạo giá trị: lớp mới, giá trị có sẵn, hàm tạo, hay bí danh
D.Theo việc giá trị có được tree-shake hay không
Đáp án: C
Theo cách tạo giá trị. Dạng đầu tạo thể hiện của một lớp. Dạng hai trả về một giá trị đã có. Dạng ba gọi một hàm factory nhận các phụ thuộc. Dạng bốn là bí danh trỏ về một nhà cung cấp khác.
Gọi inject() bên trong một callback bất đồng bộ gây lỗi. Vì sao?
A.Nó không hoạt động với các service khai providedIn: "root"
B.Nó chỉ gọi được trong injection context, tức lúc khởi tạo
C.Nó xung đột với constructor injection nếu dùng cả hai
D.Nó cần được gọi trong một hook vòng đời cụ thể
Đáp án: B
Vì nó chỉ gọi được trong ngữ cảnh tiêm phụ thuộc — thân hàm khởi tạo, khởi tạo trường, hàm factory của nhà cung cấp, và một số nơi tương tự. Sau đó ngữ cảnh không còn nên framework không biết lấy từ injector nào.
Vì sao nên tránh thao tác DOM trực tiếp qua ElementRef.nativeElement?
A.Angular không cho phép truy cập thuộc tính đó
B.Nó khiến change detection không phát hiện được thay đổi
C.Thao tác trực tiếp luôn chậm hơn thao tác qua template
D.Nó gắn code vào môi trường trình duyệt nên hỏng khi SSR
Đáp án: D
Nó gắn mã vào môi trường trình duyệt, nên hỏng khi render phía máy chủ — nơi không có DOM thật. Nó cũng mở đường cho lỗ hổng chèn mã nếu ghi nội dung chưa được làm sạch.
Angular tự động chống XSS bằng cách nào trong template?
A.Chặn mọi thẻ script trong toàn bộ ứng dụng
B.Escape mọi giá trị nội suy và sanitize giá trị gắn vào innerHTML
C.Yêu cầu khai báo Content Security Policy trong cấu hình
D.Kiểm tra dữ liệu ở phía server trước khi gửi về template
Đáp án: B
Nó thoát mọi giá trị nội suy trong template, và làm sạch các giá trị được gắn vào các ngữ cảnh nguy hiểm như nội dung HTML hay địa chỉ liên kết. Mọi giá trị bị coi là không đáng tin theo mặc định.
Pipe với pure: false có tác động gì tới hiệu năng?
A.Nó chạy bất đồng bộ nên kết quả về trễ một chu kỳ
B.Nó chạy lại ở mỗi chu kỳ change detection, không chỉ khi input đổi
C.Nó chặn change detection của các component con
D.Nó không được cache nên tốn thêm bộ nhớ
Đáp án: B
Nó chạy lại ở mỗi chu kỳ kiểm tra thay đổi, không chỉ khi đầu vào đổi tham chiếu. Với một danh sách nghìn phần tử, pipe chạy nghìn lần mỗi chu kỳ — đủ để giao diện giật rõ rệt.
Angular 16+ khuyến nghị dùng provideX() thay cho XModule.forRoot(). Lợi ích là gì?
A.Bắt buộc mọi component phải là standalone
B.Cho phép thay đổi provider lúc chạy
C.Khởi động nhanh hơn vì bỏ được bước phân giải module
D.Tree-shakable: phần không dùng bị loại khỏi bundle
Đáp án: D
Các hàm này loại bỏ được khi không dùng: trình đóng gói thấy rõ tính năng nào được gọi tới và loại phần còn lại. Module gom mọi thứ vào một khối nên trình đóng gói không biết phần nào an toàn để bỏ.
A.Chính đối tượng phần tử để so sánh theo tham chiếu
B.Một định danh ổn định và duy nhất của từng phần tử
C.Một giá trị ngẫu nhiên sinh cho mỗi lần render
D.Chỉ số của phần tử trong mảng vì nó luôn có sẵn
Đáp án: B
Một định danh ổn định và duy nhất của từng phần tử — thường là khoá chính từ cơ sở dữ liệu. Dùng chỉ số thì khi chèn một phần tử vào đầu danh sách, mọi phần tử bị coi là đã đổi và DOM bị dựng lại hết.
Đọc route param bằng snapshot gây lỗi gì khi điều hướng giữa /user/1 và /user/2?
A.Tham số trở thành chuỗi rỗng thay vì giá trị mới
B.Component được tái dùng nên giá trị cũ giữ nguyên
C.Router ném lỗi vì tham số thay đổi giữa chừng
D.Component bị dựng lại nên mất trạng thái đang có
Đáp án: B
Thành phần được tái dùng khi chỉ tham số đổi, nên bản chụp chỉ đúng ở lần khởi tạo đầu tiên. Cách sửa là đăng ký luồng tham số, hoặc bật liên kết tham số vào đầu vào của thành phần.
Functional guard (Angular 15+) khác class-based guard thế nào?
A.Nó chặn được cả request HTTP chứ không chỉ điều hướng
B.Là hàm thường dùng inject(), không cần class và decorator
C.Nó chạy phía server còn class-based chạy phía client
D.Nó không cần trả về giá trị vì router tự suy ra
Đáp án: B
Nó là một hàm thường dùng hàm tiêm phụ thuộc bên trong, không cần lớp và decorator. Nhờ đó ghép nhiều guard nhỏ lại bằng cách gọi lồng nhau, thay vì dựng một cây kế thừa lớp.
B.Lấy dữ liệu trước khi vào route; đổi lại người dùng chờ ở trang cũ
C.Phân giải đường dẫn động thành component tương ứng
D.Tải trước bundle của route để chuyển trang nhanh hơn
Đáp án: B
Lấy dữ liệu trước khi vào route, nên trang hiện ra đã có sẵn dữ liệu và không nhấp nháy trạng thái rỗng. Đổi lại người dùng chờ ở trang cũ — cảm giác là bấm rồi không có gì xảy ra một lúc.
Chiến lược preloading của router quyết định điều gì?
A.Component nào được giữ trong bộ nhớ khi rời route
B.Khi nào tải bundle của các route lazy chưa được ghé
C.Route nào được render sẵn ở phía server
D.Thứ tự các route được đăng ký vào cấu hình
Đáp án: B
Khi nào tải gói của các route tải trễ mà người dùng chưa ghé. Tải hết ngay sau khởi động thì mất lợi ích của tải trễ; không tải trước thì lần ghé đầu bị chờ tải gói.
Typed Reactive Forms (Angular 14+) mang lại lợi ích gì?
A.Form tự validate theo kiểu TypeScript đã khai
B.Giá trị form có kiểu cụ thể thay vì any, bắt lỗi lúc biên dịch
C.Form được tạo tự động từ một interface có sẵn
D.Form tự chuyển đổi kiểu dữ liệu khi người dùng nhập
Đáp án: B
Giá trị của biểu mẫu có kiểu cụ thể thay vì kiểu bất kỳ, nên trình biên dịch bắt được lỗi gõ sai tên control hay đọc sai kiểu. Trước đó những lỗi này chỉ lộ ra lúc chạy dưới dạng giá trị rỗng.
A.Khi cần validate nhiều control theo cùng một quy tắc
B.Khi một control cần nhận nhiều giá trị cùng lúc
C.Khi số lượng control thay đổi lúc chạy, ví dụ danh sách người thụ hưởng
D.Khi form được chia thành nhiều bước
Đáp án: C
Khi số lượng control thay đổi lúc chạy — danh sách người thụ hưởng, các dòng của một hoá đơn, các số điện thoại. Nhóm control thường có khoá cố định khai lúc viết mã nên không thêm bớt phần tử được.
Async validator kiểm tra email đã tồn tại chưa cần lưu ý gì?
A.Phải trả về giá trị đồng bộ nếu kiểm tra hoàn tất nhanh
B.Phải đăng ký ở cấp form thay vì cấp control
C.Debounce và huỷ request cũ; nó chạy sau khi sync validator qua hết
D.Phải chạy trước các validator đồng bộ để tiết kiệm request
Đáp án: C
Cần giảm tần suất gọi và huỷ request cũ khi có giá trị mới. Một điểm có lợi sẵn: framework chỉ chạy bộ kiểm tra bất đồng bộ sau khi các bộ kiểm tra đồng bộ đều qua — nên định dạng sai thì không tốn request nào.
Functional interceptor (Angular 15+) đăng ký thế nào?
A.Khai một provider dạng nhiều giá trị với token tương ứng
B.Truyền mảng hàm vào withInterceptors() khi provide HttpClient
C.Thêm decorator vào hàm và framework tự tìm ra
D.Đăng ký trong cấu hình route của các route cần chặn
Đáp án: B
Truyền một mảng các hàm vào một hàm cấu hình khi khai báo khách hàng HTTP. Thứ tự trong mảng chính là thứ tự chạy — nên vị trí của interceptor gắn token so với interceptor ghi log là điều cần cân nhắc.
A.Chạy một server giả trên cổng cục bộ trong lúc test
B.Thay thế HttpClient bằng một object giả tự viết
C.HttpTestingController — chặn ở tầng HttpClient và khai báo response
D.Gọi API thật nhưng trỏ vào môi trường thử nghiệm
Đáp án: C
Bộ điều khiển kiểm thử HTTP của framework. Nó chặn ở tầng khách hàng HTTP, cho phép khai báo phản hồi và kiểm tra chính request — đường dẫn, phương thức, header và thân — chứ không chỉ kiểm tra kết quả.
A.Loại đầu phát đồng bộ còn loại sau phát bất đồng bộ
B.Loại sau giữ giá trị hiện tại và phát ngay cho người mới subscribe
C.Loại sau tự hoàn tất sau khi phát giá trị đầu tiên
D.Loại sau chỉ cho phép một người subscribe tại một thời điểm
Đáp án: B
Loại sau giữ giá trị hiện tại và phát ngay cho người mới đăng ký, còn loại đầu thì không. Với loại đầu, ai đăng ký sau khi giá trị đã phát sẽ không nhận được gì cho tới lần phát kế tiếp.
A.Chạy các bài test song song để rút ngắn thời gian chạy
B.Dựng môi trường DI thu nhỏ, tạo component và thay provider
C.Đo độ bao phủ mã của bộ test
D.Sinh dữ liệu giả cho các bài test
Đáp án: B
Dựng một môi trường tiêm phụ thuộc thu nhỏ: khai các nhà cung cấp cần thiết, tạo thành phần, và thay dịch vụ thật bằng bản giả. Nhờ đó kiểm thử thành phần mà không phải sửa mã của chính nó.
Component Harness của Angular CDK giải quyết vấn đề gì trong test?
A.Đo hiệu năng render của từng component
B.Tự sinh bài test từ định nghĩa component
C.Chạy test trên nhiều trình duyệt cùng lúc
D.Test tương tác qua API ổn định thay vì selector CSS dễ vỡ
Đáp án: D
Cho phép kiểm thử tương tác qua một API ổn định — mở menu, chọn một mục, đọc giá trị — thay vì tìm phần tử bằng bộ chọn CSS. Đổi cấu trúc DOM bên trong thành phần khi đó không làm hỏng bài kiểm thử.
Application builder (esbuild) thay thế builder cũ mang lại gì?
A.Thay thế Angular CLI bằng một công cụ mới
B.Bỏ hoàn toàn bước biên dịch TypeScript
C.Build nhanh hơn nhiều và gộp SSR vào cùng một builder
D.Cho phép chạy ứng dụng mà không cần build
Đáp án: C
Build nhanh hơn nhiều nhờ một bundler viết bằng Go, và gộp cả render phía máy chủ vào cùng một bộ dựng. Trước đó cấu hình render máy chủ cần một bộ dựng riêng và nhiều bước thủ công.
C.Cảnh báo hoặc fail build khi bundle vượt ngưỡng dung lượng
D.Giới hạn thời gian tối đa cho quá trình build
Đáp án: C
Cảnh báo hoặc làm hỏng bản build khi dung lượng gói vượt ngưỡng đặt trước. Không có nó, gói phình dần qua từng lần thêm thư viện mà không ai để ý cho tới khi trang chậm rõ rệt.
Incremental hydration trong Angular mới cho phép gì?
A.Hydrate dần từng component theo thứ tự trong DOM
B.Chia quá trình hydrate thành nhiều frame để không chặn UI
C.Chỉ hydrate phần được tương tác, phần còn lại giữ HTML tĩnh
D.Bỏ hoàn toàn bước hydrate và chạy như trang tĩnh
Đáp án: C
Chỉ kích hoạt phần mà người dùng thật sự tương tác tới, còn lại giữ nguyên HTML tĩnh từ máy chủ. Kích hoạt cả trang tốn nhiều thời gian CPU trên thiết bị yếu, dù phần lớn nội dung không hề tương tác.
Route con (children) và named outlet khác nhau thế nào?
A.Named outlet chỉ dùng được ở cấp route gốc
B.Route con dùng cho lazy load còn named outlet cho eager load
C.Route con lồng theo URL; named outlet render song song ở vị trí riêng
D.Route con chia sẻ component còn named outlet tạo component mới
Đáp án: C
Route con lồng theo đường dẫn: đường dẫn cha cộng đường dẫn con, và thành phần con hiện trong ổ cắm của thành phần cha. Ổ cắm có tên render song song ở một vị trí riêng, và xuất hiện trong đường dẫn dưới dạng một đoạn phụ trong ngoặc.
Theo dõi valueChanges của form để tự động lưu nháp cần thêm gì?
A.Phải gọi phương thức cập nhật giá trị sau mỗi lần thay đổi
B.Phải chuyển form sang template-driven để theo dõi được
C.Chỉ cần đăng ký và gọi API lưu trong hàm xử lý
D.Debounce, bỏ giá trị trùng, và huỷ đăng ký khi component bị huỷ
Đáp án: D
Ba thứ: giảm tần suất để không lưu ở mỗi ký tự, bỏ các giá trị trùng nhau, và huỷ đăng ký khi thành phần bị huỷ. Thiếu cái cuối là một trong những nguồn rò rỉ bộ nhớ phổ biến nhất.
Chuyển một dự án Angular cũ sang standalone component nên làm thế nào?
A.Không cần chuyển; NgModule vẫn được hỗ trợ vĩnh viễn
B.Xoá hết NgModule rồi sửa các lỗi biên dịch phát sinh
C.Tạo dự án mới rồi copy từng component sang
D.Chạy schematic migration của CLI theo từng bước
Đáp án: D
Chạy lược đồ chuyển đổi của công cụ dòng lệnh theo ba bước: chuyển các thành phần sang dạng độc lập, gỡ các module không còn cần, rồi chuyển ứng dụng sang khởi động không dùng module gốc.