Build Custom Structural Directives in Angular like a hero 😎
Tags: angular, directives, customstructuraldirective, javascript
Published: 2022-08-01 05:05:10

## Introduction
Angular comes with some built-in directives.

**Structural Directive** can be used to manipulate the HTML structure in the DOM. Using them, we can change the structure of part of the DOM.

1. *ngIf
2. *ngForOf
3. *ngSwitch

## Creating a custom structural directive
Why custom structural directive?

> We have build in structural directive that satisfies our solution, what if we might come across a case that the ones provided with the framework don't solve. so here comes the custom structural directive.


So, in this article we will try cloning the `*ngIf` structural directive

Let's understand how we can create `*ngIf` structural directive

## Let's create a project using Angular CLI

```
// use this command to create new angular project
ng new project-name
```

```
// create a module 
ng generate module custom-if
```
Now let's create a custom directive

```
// create a custom directive
ng generate directive
```

generated directive should look like this

```
import { Directive } from '@angular/core';

@Directive({
  selector: '[customIf]',
})
export class customIfDirective {
  constructor() {}
}
```

Let's implement the basic functionality of displaying the content if passed value is true

```
<h2 *customIf="true">My visible content</h2>
<h2 *customIf="false">My hidden content</h2>
```
To achieve that, we need a couple of elements:

an input that will determine whether to show or hide the content `(@Input)`

a reference to the template that we want to conditionally display `(TemplateRef)`

a container that will provide us with access to Angular's view `(ViewContainerRef)`

The `@input` can be just a regular class field decorators property with Angular's. For it to work as it does in the example code shown` *customIf="true"`, we need to name the property the same as the attribute's selector:

```
import { Directive, Input } from '@angular/core';

@Directive({
  selector: '[customIf]',
})
export class IfDirective {
 @Input() set customIf(show: boolean) {
    //code goes here
  }

  constructor() {}
}
```

Now the directive has the value to display the content, we also need TemplateRef and ViewContainerRef instances. We can do that by injecting them by importing from `@angular/core`:

```
import { TemplateRef, ViewContainerRef } from '@angular/core';

constructor(
    private templateRef: TemplateRef<unknown>,
    private vcr: ViewContainerRef
  ) {}
```
Now, we can make a use of `ViewContainerRef's` reference `this.vcr.createEmbeddedView(this.templateRef)` method to display and `this.vcr.clear()` method to remove the content.

This is how the final code looks like

```
@Directive({
  selector: '[customIf]',
})
export class IfDirective {
@Input() set customIf(value: boolean) {
    this._renderTemplate(value)l
  }

constructor(
    private templateRef: TemplateRef<unknown>,
    private vcr: ViewContainerRef
  ) {}

private _renderTemplate(show: boolean) {
    this.vcr.clear();
    if (show) {
      this.vcr.createEmbeddedView(this.templateRef);
    }
  }
}
```
Wohoo! 🥳  we have successfully create `*customIf` now let's focus on creating else template
So, let us understand how it works?

> How do we achieve this behaviour in our custom directive? This is where understanding the "syntactic sugar" that stands behind the structural directives is crucial.


![Custom Structural Directives](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6yorwrdclvmoi3a7rlb.png)

If we observe the above image example, it means that the else property is actually becoming ngIfElse input parameter.

So, we can access the else template by `selector (customIf) + else (Else)` = `customIfElse`

```
@Input() customIfElse?: TemplateRef<unknown>;
```

Now, the code looks like 

```
@Directive({
  selector: '[customIf]',
})
export class IfDirective {
@Input() set customIf(value: boolean) {
    this._renderTemplate(value)l
  }
@Input() customIfElse?: TemplateRef<unknown>;
constructor(
    private templateRef: TemplateRef<unknown>,
    private vcr: ViewContainerRef
  ) {}

private _renderTemplate(show: boolean) {
    this.vcr.clear();
    if (show) {
      this.vcr.createEmbeddedView(this.templateRef);
    } else if (this.customIfElse) {
      this.vcr.createEmbeddedView(this.customIfElse);
    }
  }
}
```
## Summary
In this article, we've learnt how to create a simple custom structural directive that handles additional inputs. We've covered the syntactic sugar that stands behind the structural directive, and how it translates into directive's inputs.

In case you have any questions, you can always tweet or DM me at [@DeekshithrajB](https://twitter.com/deekshithrajB). I'm always happy to help!

Connect with me over linkedIn: [Deekshith Raj Basa](https://www.linkedin.com/in/deekshith-raj-basa/)