Hello to this little introduction about Custom directives in angular.
What is Directive?
In angular a directive is special kind of component but without any template referencing directly. Meaning A component is directive with template binding out of the box. A directive can be useful for any DOM manipulation in application. In fact, angular is recommending to use custom-directive when you want to safely manipulate DOM.
Types of directive?
- Component directive. any component in angular with @Component decorator is special kind of directive, and we called it as a component directive.
- Attribute directive. Angular provides [ngClass], [ngStyle] which are useful for changing appearance of element.
- Structural directive. Angular provides *ngIf, *ngFor, *ngSwitch are all called as structural directive because of all are used to manipulate DOM structure by adding or removing element directly.
- Custom directive.
this is directive we can used in angular for custom DOM logic
implementation. we can create custom directive using angular-cli by firing
ng generate directive <directive-name>
and custom directive is generated with @Direvtive() decorator in class. By default scope is ngModule level.
Today, we are going to learn how to implement our own *ngIf using custom-directive.
now lets create custom directive by firing this command..
ng generate directive custom-directive-if
Above command will generate directive like this..
import { Directive } from '@angular/core';
@Directive({
selector: '[appCustomDirectiveIf]'
})
export class CustomDirectiveIfDirective {
constructor() { }
}
now lets create add below code to app.component.html
<div class="row p-1">
<div class="col-6 d-flex align-items-center">
<input #checkboxValue id="checkBox" type="checkbox" (change)="onCheckboxChanged(checkboxValue)">
<label class="ml-1 cursor" for="checkBox"> show/hide </label>
</div>
<div *appCustomDirectiveIf="show" class="col-6 shadow-color-blue">
Custom If directive content displayed...
</div>
</div>
Above code note we are using our own custom implementation of directive to replace *ngIf or understand properly how to manipulate DOM node properly. we are using *appCustomDirectiveIf
and passing reference of show
to it which is coming from checkbox. When user checked checkbox show becomes true
by calling (change) event of input type="checkbox", so we call onCheckboxChanged()
and passes reference of input-checkbox. Then after checkbox value is passed to out custom directive as a @Input().
now implement custom-directive
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appCustomDirectiveIf]'
})
export class CustomDirectiveIfDirective {
@Input()
set appCustomDirectiveIf(show: boolean){
show ? this.container.createEmbeddedView(this.templateRef) : this.container.clear();
}
constructor(private templateRef: TemplateRef<any>,
private container: ViewContainerRef) { }
}
We are injecting 1. TemplateRef. TemplateRef is the one we applied our custom directive in template. means the template node reference on which we are applying custom-directive.
- ViewContainerRef. In angular we are not directly manipulate DOM or accessing DOM structure. Because angular is plateform independent meaning same code base you can use in ng-Universal or in IONIC. SO, accessing DOM directly you break code to run in other plateform where DOM is not available. So to safely access DOM structure angular creates their own VIEW hierarchy and based on that DOM is created or removed. To access VIEW hierarchy angular provide
ViewContainerRef
, and some methods to add or remove element from view and view directly bounded to DOM so it will update DOM for us automatically.
Now, when we pass true to @Input() view.createEmbeddedView() method is called and it will create new DOM node element in current element hierarchy. and if value is false then we clear out view hierarchy and DOM updates occurs too.
You can find out working code in this link
Top comments (3)
This is adding multiple instances of the component when the condition changes for me. Any idea why? If it matters, the condition is an observable
I'm facing the same issue now. The only solution I found was adding a control variable like
isHidden: boolean
and changing its value whenever I hide or show the element. By doing this, when I'm about to show the element in case the condition is true, I validade the value of this variable first.What if we do like this ... First we clear viewContainer regardless of condition of show variable. Then, we create new view based on show true case only?