Extending Angular: Creating Custom Directives
Unlock Angular's full potential by creating your own reusable directives to extend the power of your HTML.
Attribute Directives: Modifying Behavior
Attribute directives change the appearance or behavior of a DOM element. You create them by defining a class with the `@Directive` decorator and a CSS selector in brackets (e.g., `[appHighlight]`). They are perfect for tasks like applying dynamic styles, handling custom events, or integrating third-party libraries.
Structural Directives: Shaping the DOM
Structural directives shape or reshape the DOM's structure, typically by adding, removing, or manipulating elements. They are easy to recognize by the leading asterisk (`*`) in their syntax, like `*ngIf` or `*ngFor`. Creating your own, like `*appUnless`, involves using `TemplateRef` to access the host element's content and `ViewContainerRef` to control where it's rendered.
Purpose: Creating Reusable Logic
The purpose of custom directives is to create reusable, encapsulated logic that extends HTML. Instead of writing complex logic directly in your components, you can abstract it into a clean, declarative directive. This makes your component templates more readable and your application easier to maintain and scale.
Practice Zone
Interactive Test 1: Match the Type
Match the directive type to its primary function.
Arrastra en el orden correspondiente.
Arrastra las opciones:
Completa el código:
Interactive Test 2: Complete the Code
Rellena los huecos en cada casilla.
<p ="'yellow'"> This paragraph is highlighted. </p> <div ="!isLoggedIn"> This content is shown only if the user is not logged in. </div>
Practice Example: Code Editor
Create a simple attribute directive named `appHighlight` that changes the background color of its host element. Make the color configurable via an input property.
Directives in Action
Custom directives are powerful tools for creating clean, declarative templates. Here are some practical examples of how they can be used to solve common problems.
1. Role-Based Access Control
A structural directive can cleanly show or hide elements based on a user's role. This keeps your permission logic out of the component class and makes the template highly readable.
// In your template:
<button *ifHasRole="'admin'">Delete User</button>
// The directive logic:
@Input() set ifHasRole(role: string) {
if (this.userService.currentUser.hasRole(role)) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
2. Custom Tooltips
An attribute directive is perfect for attaching custom tooltips. It can handle all the logic for positioning and showing/hiding the tooltip on mouse events, keeping the component clean.
<button [appTooltip]="'Save your changes'">Save</button>
// Directive Logic (simplified):
@HostListener('mouseenter') onMouseEnter() {
// Create and show tooltip element
}
@HostListener('mouseleave') onMouseLeave() {
// Destroy tooltip element
}
3. Draggable Elements
Complex user interactions like dragging an element can be encapsulated in a directive. By listening to `mousedown`, `mousemove`, and `mouseup` events, the directive can manage the element's position without cluttering the component.
<div appDraggable class="draggable-box">Drag Me!</div>
Practical Takeaway: Think of directives as reusable "recipes" for DOM behavior. By creating them, you build a powerful, application-specific library that accelerates development and improves code quality.
Custom Directives Glossary
- @Directive
- A decorator that marks a class as an Angular directive and provides configuration metadata, most importantly the `selector` that identifies where the directive is applied in a template.
- ElementRef
- A wrapper around a native DOM element that allows for direct access. It should be used with caution, with `Renderer2` being the preferred method for DOM manipulation.
- Renderer2
- A service that provides a platform-independent API for safely manipulating DOM elements without touching `ElementRef.nativeElement` directly. This is crucial for environments where there is no browser DOM (e.g., server-side rendering).
- @Input
- A decorator that marks a class field as an input property, allowing data to be passed from a parent component's template into the directive.
- TemplateRef & ViewContainerRef
- The core tools for structural directives. `TemplateRef` represents the embedded template (the content the directive is applied to), and `ViewContainerRef` represents the container in the DOM where the template can be attached or detached.