Course Content
Introduction to Angular
Introduction to Angular
Creating Custom Directives in Angular
Angular comes with a set of built-in directives like ngIf
, ngFor
, and ngClass
. But you can also create your own custom directive to handle specific tasks in your application. Let's walk through how to build one with a practical example.
Generate the Custom Directive
First, it's a good practice to organize your code by creating a dedicated folder for your directives. Let's call it directives
.
This command creates a new folder named directives
inside the app
directory and adds the new directive file inside it:
highlight-on-complete.directive.ts
β contains the directive's logic;highlight-on-complete.directive.spec.ts
β unit test file (you can delete it if not needed).
Here's what the basic structure of the directive looks like:
highlight-on-complete
import { Directive } from '@angular/core'; @Directive({ selector: '[appHighlightOnComplete]' }) export class HighlightOnCompleteDirective { constructor() {} }
Define What the Directive Should Do
This directive will highlight a task element in green if it's marked as completed. Otherwise, it will clear the styles.
To tell Angular that this class is a directive, we decorate it with @Directive
:
ts
The selector [appHighlightOnComplete]
means the directive will be used as an attribute, not as a tag or structural directive.
In your HTML, you'll apply it like this:
ts
Make the Directive React to Changes
To detect changes to the completed input, we implement the OnChanges
interface:
highlight-on-complete
export class HighlightOnCompleteDirective implements OnChanges {}
We also define an input property to receive the value from the component:
highlight-on-complete
export class HighlightOnCompleteDirective implements OnChanges { @Input('appHighlightOnComplete') completed: boolean = true; }
What this does:
Informs Angular that the value will be provided from the template (earlier, we passed task.complete from the template);
Binds the directive's internal completed property to the value passed in from the template;
Sets a default value of true (which will be overridden once actual data is received).
Access the DOM Safely
Angular uses dependency injection to provide access to the DOM and rendering tools.
In the constructor, we inject:
highlight-on-complete
export class HighlightOnCompleteDirective implements OnChanges { @Input('appHighlightOnComplete') completed: boolean = true; constructor(private el: ElementRef, private renderer: Renderer2) {} }
ElementRef
gives us a reference to the host DOM element. Renderer2
allows us to safely modify styles and attributes without directly manipulating the DOM.
React to Changes with ngOnChanges
Now let's implement the main logic in ngOnChanges
, which runs whenever the input value changes.
Full implementation:
highlight-on-complete
@Directive({ selector: '[appHighlightOnComplete]' }) export class HighlightOnCompleteDirective implements OnChanges { @Input('appHighlightOnComplete') completed: boolean = true; constructor(private el: ElementRef, private renderer: Renderer2) {} ngOnChanges(changes: SimpleChanges): void { if (this.completed) { this.renderer.setStyle(this.el.nativeElement, 'border', '2px solid green'); this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', '#e6ffe6'); } else { this.renderer.removeStyle(this.el.nativeElement, 'border'); this.renderer.removeStyle(this.el.nativeElement, 'backgroundColor'); } } }
The ngOnChanges
method is triggered whenever Angular detects changes to the directive's input properties.
In this case, it responds to updates to the completed
value passed from the template. If completed
is true
, the directive adds a green border and a light green background to the element. If it's false
, those styles are removed, returning the element to its original appearance. This provides a visual indication of completed tasks.
This custom directive lets you encapsulate style behavior in a reusable, clean way. You can now apply it to any element in your app, without duplicating logic across components. It's a great example of how Angular's directive system can help you write more modular and maintainable code.
Thanks for your feedback!