Directives

5 questions found

What is a directive in Angular and what are the three main types?

Beginner
A directive is a class that adds behavior to an element in your template. Component directives are directives with their own template. Structural directives, like the older asterisk ngIf, change the layout by adding or removing elements. Attribute directives, like ngClass, change the appearance or behavior of an existing element without adding or removing it.
// Attribute directive example
<div [ngClass]="{ active: isActive }">Content</div>

// Structural directive example
<p *ngIf="isVisible">This text is conditionally shown</p>
Real-world example A navigation menu highlights the currently active link using the ngClass attribute directive, while a separate section of the page is conditionally shown or hidden using a structural directive.

Common follow-ups: What is the difference between a structural directive and a component, given both can affect the template?;Why does a structural directive's name in older syntax start with an asterisk?

New Control Flow Syntax (@if @for & @switch);Components & Templates

How would you create a custom attribute directive in Angular?

Intermediate
You create a class decorated with the Directive decorator, specifying a selector that matches the attribute you want to use in templates, then use dependency injection to get a reference to the host element and modify its behavior or appearance.
import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({ selector: '[appHighlight]', standalone: true })
export class HighlightDirective {
  constructor(el: ElementRef, renderer: Renderer2) {
    renderer.setStyle(el.nativeElement, 'backgroundColor', 'yellow');
  }
}

// Used as: <p appHighlight>This text has a yellow background</p>
Real-world example A team builds a custom highlight directive to visually mark important text throughout their app, reusing the exact same directive on any element that needs the same yellow background treatment.

Common follow-ups: Why is Renderer2 recommended over directly manipulating the DOM element yourself?;How would you make this directive's highlight color configurable through an input?

Services & Dependency Injection;Angular Style Guide & Best Practices

How does the HostListener decorator let a directive respond to events on its host element?

Intermediate
HostListener lets you attach an event listener directly to the element a directive is applied to, without needing to manually add event bindings in a template, making it useful for directives that need to react to things like mouse events or key presses on their host element.
import { Directive, HostListener, ElementRef, Renderer2 } from '@angular/core';

@Directive({ selector: '[appHoverHighlight]', standalone: true })
export class HoverHighlightDirective {
  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('mouseenter') onMouseEnter() {
    this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'yellow');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'transparent');
  }
}
Real-world example A custom directive automatically highlights any element it is applied to whenever a user hovers their mouse over it, using HostListener to detect the mouseenter and mouseleave events directly.

Common follow-ups: Can HostListener also listen for global events, like window resize, rather than just events on the host element?;How does HostBinding complement HostListener for updating the host element's own properties?

Components & Templates;Angular Animations

How would you build a custom structural directive similar to ngIf from scratch?

Advanced
You inject a TemplateRef, representing the content the directive is applied to, and a ViewContainerRef, representing where that content can be inserted, then use createEmbeddedView and clear methods to add or remove the template's content based on your own custom condition.
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appUnless]', standalone: true })
export class UnlessDirective {
  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {}

  @Input() set appUnless(condition: boolean) {
    if (!condition) this.viewContainer.createEmbeddedView(this.templateRef);
    else this.viewContainer.clear();
  }
}
Real-world example A team builds a custom appUnless structural directive that shows content only when a condition is false, the exact opposite of ngIf, giving them a cleaner way to express certain conditions in their templates.

Common follow-ups: How does the built in at if control flow syntax compare in performance to a custom structural directive like this?;What exactly does createEmbeddedView do behind the scenes?

New Control Flow Syntax (@if @for & @switch);Components & Templates

What is the ngFor structural directive used for, and how does the newer at for syntax compare to it?

Beginner
ngFor, and its newer replacement the at for control flow block, repeats a piece of template content once for every item in a list, letting you display a collection of data such as a list of products or names, with the newer syntax additionally requiring a track expression to help Angular efficiently update the list.
@Component({
  selector: 'app-todo-list',
  template: `
    @for (todo of todos; track todo.id) {
      <li>{{ todo.text }}</li>
    }
  `
})
export class TodoListComponent {
  todos = [{ id: 1, text: 'Buy milk' }, { id: 2, text: 'Walk the dog' }];
}
Real-world example A to do list app displays every task using the newer at for syntax, tracking each item by its unique id so Angular can efficiently update the list even as tasks are added or removed.

Common follow-ups: Why does the at for syntax require a track expression while the older ngFor did not strictly require trackBy?;What performance benefit does properly tracking items by a unique id actually provide?

New Control Flow Syntax (@if @for & @switch);Performance & Lazy Loading