A directive is a class that Angular attaches to an element (or an <ng-template>) to add behavior, change styling, or control whether a chunk of template exists at all. Interview focus: the 3 directive categories, how structural directives desugar from * syntax into <ng-template>, and how to build safe custom directives (HostBinding/HostListener, Renderer2, TemplateRef/ViewContainerRef). Framework focus: Angular templates + standalone components, @Input/@Output, and RxJS/async pipe patterns.
Angular directives: structural vs attribute vs components — and what the * syntax really does
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
Core idea
A directive is a class that Angular instantiates when it matches a selector in a template. The directive can:
• add behavior (listen to events, update host properties)
• change styling (classes/styles/attributes)
• control the DOM tree by creating/destroying embedded views (structural directives).
Category | What it does | How it shows up | Typical examples |
|---|---|---|---|
Component | A directive with its own template. | Used as an element/tag. |
|
Attribute directive | Changes host element behavior/appearance without changing DOM structure. | Used as an attribute selector. |
|
Structural directive | Adds/removes a block of template by creating/destroying an embedded view. | Usually appears with |
|
What the * really means (microsyntax)* is just syntax sugar. Angular rewrites it into an <ng-template> and binds inputs to the directive on that template.
<!-- Shorthand -->
<div *ngIf="isAdmin">Admin</div>
<!-- Rough desugaring -->
<ng-template [ngIf]="isAdmin">
<div>Admin</div>
</ng-template>
<!-- With else -->
<div *ngIf="isAdmin; else notAdmin">Admin</div>
<ng-template #notAdmin>Not admin</ng-template>
Structural directives are special because… | Concrete consequence |
|---|---|
They operate on | They can create/destroy DOM, component instances, listeners, and run |
Only one | Because the host becomes an |
Custom attribute directive (typical interview example)
Use HostBinding/HostListener (or Renderer2) to affect the host. Avoid direct DOM where possible (SSR/testing safety).
import { Directive, HostBinding, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]',
standalone: true
})
export class HighlightDirective {
@Input() appHighlight = 'yellow';
@HostBinding('style.backgroundColor') private bg = '';
@HostListener('mouseenter') onEnter() {
this.bg = this.appHighlight;
}
@HostListener('mouseleave') onLeave() {
this.bg = '';
}
}
<p [appHighlight]="'gold'">Hover me</p>
Custom structural directive (the “real” senior signal)
Structural directives control a template block. They inject TemplateRef (what to render) and ViewContainerRef (where to render).
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appIf]',
standalone: true
})
export class AppIfDirective {
private hasView = false;
constructor(
private tpl: TemplateRef<unknown>,
private vcr: ViewContainerRef
) {}
@Input() set appIf(condition: boolean) {
if (condition && !this.hasView) {
this.vcr.createEmbeddedView(this.tpl);
this.hasView = true;
return;
}
if (!condition && this.hasView) {
this.vcr.clear();
this.hasView = false;
}
}
}
<div *appIf="isVisible">Visible</div>
<!-- desugars to -->
<ng-template [appIf]="isVisible">
<div>Visible</div>
</ng-template>
Pitfall | What goes wrong | Better approach |
|---|---|---|
Direct DOM mutation in directives | Breaks SSR/testing; can bypass Angular rendering assumptions | Prefer HostBinding/HostListener or Renderer2; keep DOM work minimal |
Using structural directive when you need state preserved | It destroys/recreates component instances (state resets, subscriptions re-run) | Use |
Multiple | Template rewrite conflict | Wrap with |
Heavy work in directives without OnPush-friendly patterns | Unnecessary change detection / jank in large views | Keep directives small; push heavy logic to services/facades; use async/signal patterns |
Interview one-liners to say |
|---|
“Components are directives with templates; attribute directives modify the host; structural directives create/destroy embedded views.” |
“The * is syntax sugar for <ng-template> + directive inputs.” |
“Structural directives use TemplateRef and ViewContainerRef to manage embedded views.” |
“Prefer HostBinding/HostListener (or Renderer2) over direct DOM access.” |
Directives are Angular’s way to attach behavior to templates. Attribute directives change an existing element; structural directives change the rendered tree by creating/destroying embedded views; components are directives with templates. The key senior detail: * desugars into <ng-template>, and structural directives are basically TemplateRef + ViewContainerRef orchestration.