What is decorator in Angular?

Decorator In Angular

What is a decorator in Angular?

Decorator is a declarative way of providing metadata information to typescript compiler. It is declared by @.
NOTE  Decorators are an experimental feature that may change in future releases.
As per the Typescript

Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members. Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript.

By the end of this tutorial you will be able to answer following 
  • What are decorators in Typescript?
  • What is the difference between decorators and annotations?
  • How can I use decorators?
  • What is the syntax for using a decorator?
  • How does a typescript compiler process decorators?

How to enable decorator?

To enable experimental support for decorators, you must enable the experimentalDecorators compiler option either on the command line or in your tsconfig.json:
{
    "compilerOptions": {
        "target": "ES6",
        "experimentalDecorators": true
    }
}

Types of decorator

There are four types of decorator in Angular
  1. Class Decorator
  2. Method Decorator
  3. Field Decorator
  4. Parameter Decorator

Class Decorator

Angular provide some class level decorator like Component and NgModule .
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  data:boolean=false;
}

Field Decorator

Angular offers some field-level decorator like @Input and @Output.
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
 @Input() data:Array<any>;
}

Method Decorator

Angular offers some method level decorator like HostBinding and HostListener.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  @HostListener('mouseover')
  onMouseOver($event){
    
  }
}

Parameter Decorator

Angular offers some parameter level decorator like @Inject.
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

    constructor(@Inject(SomeService) service){

    }
  }

Execution order of decorator

As per the typescript website, There is a well-defined order to how decorators applied to various declarations inside of a class are utilised:
  1. Parameter Decorators, followed by Method, Accessor, or Property Decorators, is used for each instance member.
  2. Parameter Decorators, followed by Method, Accessor, or Property Decorators are used for each static member.
  3. Parameter Decorators are used for the constructor.
  4. Class Decorators are used for the class.

How to create custom decorator in Angular

You can create your decorator if your requirement doesn’t fit with existing decorator

Method Decorator

Let’s suppose you want to benchmark your function in Angular. In the naive approach, you can wrap your function in start and end time and then you can calculate the time. This approach will work, but it requires a lot of changes in your code. The second and best approach is the declarative way. Just create a custom decorator and add an annotation to your method.
For example, take the following example.
function benchMark(): MethodDecorator {
return function(target: Function, key: string, descriptor: any) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args: any[]) {
    const start = new Date().getTime();
    const result = originalMethod.apply(this, args);
    const end = new Date().getTime();
    console.log(` ${key} execute in  ${(end - start) / 1000} ms`);

    return result;
  };
  return descriptor;
};
}
And you can use the above decorator as shown below
import { Component } from "@angular/core";

function benchMark(): MethodDecorator {
  return function(target: Function, key: string, descriptor: any) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
      const start = new Date().getTime();
      const result = originalMethod.apply(this, args);
      const end = new Date().getTime();
      console.log(` ${key} execute in  ${(end - start) / 1000} ms`);

      return result;
    };
    return descriptor;
  };
}

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  name = "Angular";

  @benchMark()
  ngOnInit() {
    this.doSomeWork();
  }
  doSomeWork() {
    for (let i = 0; i < 10000000; i++) {}
  }
}

Class Decorator

Let’s consider you want to add createdDate and updatedDate to every model of your application for auditing purpose. In this case, you can create a class decorator.
See the below code for the implementation of the class decorator.
function auditLog<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    createdDate = new Date();
  };
}
@auditLog
export class User {
  firstName: string;
  lastName: string;
  constructor(firstName: string, lastName: string) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}
How to use
import { Component, OnInit } from "@angular/core";

function auditLog<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    createdDate = new Date();
  };
}
@auditLog
export class User {
  firstName: string;
  lastName: string;
  constructor(firstName: string, lastName: string) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}

@Component({
  selector: "app-class",
  templateUrl: "./class.component.html",
  styleUrls: ["./class.component.css"]
})
export class ClassComponent implements OnInit {
  constructor() {}

  ngOnInit() {
    const user = new User("John", "Doe");
    console.log(JSON.stringify(user));
  }
}

Please do not post any spam link in the comment box😊

إرسال تعليق (0)
أحدث أقدم