DEV Community

Angular Kenya
Angular Kenya

Posted on

How To Create A Custom Directive in Angular

Structural directives allow us to change the DOM In different ways: By adding, changing, or removing all the elements on the page. They are added as an attribute in the HTML element. The directive should always be prefixed with an * to make them easy to distinguish. Angular provides some built-in directives such as ngIf, ngFor, etc.

💡 The asterisk (*) is syntactic sugar that wraps under the hood of our HTML, where we attach this directive to the ng-template.

Let’s Create Our First Directive

We will create a directive that shows some content after a period of time.

First, you need to run this command on the Angular CLI to create a directive class:

/* ng generate directive name-of-directive */
ng generate directive showContentAfterDelay
Enter fullscreen mode Exit fullscreen mode

Add the following code on the directive class generated:

import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[ozarksShowContent]'
})
export class ShowContentDirective implements OnInit {

  @Input('ozarksShowContent') delay = 0

  constructor(private viewContainerRef: ViewContainerRef,
              private  template: TemplateRef<any>) 
              { }

  ngOnInit(): void {
      this.viewContainerRef.createEmbeddedView(this.template);
      setTimeout(() => {
        // cleans up the view cointainer ref
        this.viewContainerRef.clear();
      }, this.delay)  
  }
} 
Enter fullscreen mode Exit fullscreen mode

The Directive provides the functionality of the @Directive decorator in which we give its property selector to ozarksShowContent so that we can use this selector anywhere in the application.

We pass data to the directive using the @Input() decorator - it's a property that the parent component (Parent) passes to the child component.

We inject the ViewCointainerRef and TemplateRef in the constructor. The ViewContainerRef represents a container where one or more views can be attached, while the TemplateRef is a way to reference the ng-template in the component/directive.

On the template, we add our custom directive like this:

<h1>Welcome to the Lazy-O Motel</h1>
<section *ozarksShowContent="5000">
  <h1>Let Me See You!</h1></section>
Enter fullscreen mode Exit fullscreen mode

If you try to bind the input value to the template like this it won’t work because Angular tries to resolve the input as a property of the section which does not exist.

<!--This will not work-->

<h1>Welcome to the Lazy-O Motel</h1>
<section *ozarksShowContent [delay]="5000">
  <h1>Let Me See You!</h1> 
</section>
Enter fullscreen mode Exit fullscreen mode

In case you would like to render content after the 5 seconds, this is how you implement it:

On the .ts file

import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[ozarksShowContent]'
})
export class ShowContentDirective implements OnInit {

  @Input('ozarksShowContent') delay = 0

  // showing content after some time
  @Input("ozarksShowContentThen") placeholder: TemplateRef<any> = null;

  constructor(private viewContainerRef: ViewContainerRef,
              private  template: TemplateRef<any>) 
              { }

  ngOnInit(): void {
      this.viewContainerRef.createEmbeddedView(this.template);
      setTimeout(() => {
        // cleans up the view cointainer ref
        this.viewContainerRef.clear();
        if(this.placeholder){
          // if the value is true,show the template
          this.viewContainerRef.createEmbeddedView(this.placeholder )
        }
      }, this.delay)

  }
}
Enter fullscreen mode Exit fullscreen mode

On the .html file

<section *ozarksShowContent="5000; then placeholder">
  <h1>Let Me See You!</h1> 
</section>

<ng-template #placeholder>
  <mat-toolbar color="primary">
    <mat-icon>hotel</mat-icon> &nbsp; &nbsp;
    <span>Welcome to the Lazy-O Motel </span>
  </mat-toolbar>
</ng-template>
Enter fullscreen mode Exit fullscreen mode

Conclusion

Custom directives can be helpful when custom logic is involved in the DOM element. For example, in user role management or you may want to show some aspects to different customers, say you have premium customers, free-plan customers, etc., on a web application. When inbuilt directives don't give the required output, we can always write a custom directive.

Happy Learning!

Oldest comments (0)