We use Angular Decorators to Provide metadata to a class declaration, method, accessor, property, or parameter in Angular. We use it at many places in our Angular App. We use it to decorate components, directives, Angular Modules, etc. In this article, let us learn what is Angular Decorator, Why it is needed, and How to create a custom Angular Decorator. We also learn list of built-in Decorators that Angular Supports.
Table of Contents
Angular Decorators
An Angular Decorator is a function, using which we attach metadata to a class declaration, method, accessor, property, or parameter.
We apply the decorator using the form @expression, where expression is the name of the decorator.
For Example, @Component
is an Angular Decorator, which we attach to an Angular Component. When Angular sees the @Component
decorator applied to a class, it treats the class as a component class. In the following example, it is the @Component
decorator that makes AppComponent
an Angular Component. Without the decorator, AppComponent is just like any other class.
1 2 3 4 5 6 7 | @Component({ }) export class AppComponent { title = 'app'; } |
The decorator is a Typescript feature and it is still not part of the Javascript. It is still in the Proposal stage.
To enable Angular Decorators, we need to add the experimentalDecorators
to the tsconfig.json
file. The ng new
command automatically adds this for us.
1 2 3 4 5 6 7 8 | { "compilerOptions": { "target": "ES5", "experimentalDecorators": true } } |
Why we need Angular Decorators
Angular uses the Decorators to Provide metadata to the class, method, or property.
For example, the AppComponent
must know where to find its template. We do that by using the templateUrl
parameter of the @Component
directive. The @Component
decorator also accepts the values for styleUrls
, encapsulation
, changeDetection
, etc, which Angular uses to configure the component.
1 2 3 4 5 6 7 | @Component({ templateUrl: './app.component.html', }) export class AppComponent { |
To understand how a decorator works let us build a class decorator named simpleDecorator
.
Creating a new Decorator in Angular
We use the decorator in the form @expression, where expression is the name of the decorator and it must be evaluate to a function.
In the following example, we create a function simpleDecorator
. We will use it to decorate the AppComponent
class. The function does not take any arguments.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import { Component, VERSION } from '@angular/core'; @simpleDecorator @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { name = 'Angular ' + VERSION.major; constructor() { console.log('Hello from Class constructor'); } ngOnInit() { console.log((this as any).value1); console.log((this as any).value2); } } function simpleDecorator(target: any) { console.log('Hello from Decorator'); Object.defineProperty(target.prototype, 'value1', { value: 100, writable: false }); Object.defineProperty(target.prototype, 'value2', { value: 200, writable: false }); } **** Console *** Hello from Decorator Hello from Class constructor 100 200 |
You can refer StackBlitz for the complete code.
As we said earlier, the decorator
is a regular JavaScript function. Since we are using it using it on class, It gets the instance of the AppComponent
as a argument (target
)
1 2 3 4 5 6 | function simpleDecorator(target: any) { console.log('Hello from Decorator'); //target is instance of AppComponent |
Inside the function, we add two custom properties value1
& value2
to our AppComponent
. Note that we use the defineProperty
property to add a new property to the component class. Also, we add it to the prototype property of the class
1 2 3 4 5 6 7 8 9 10 11 | Object.defineProperty(target.prototype, 'value1', { value: 100, writable: false }); Object.defineProperty(target.prototype, 'value2', { value: 200, writable: false }); |
Now, we can use it to Decorate
our AppComponent
1 2 3 4 5 6 7 8 9 | @simpleDecorator @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { |
Inside the component, we can access the new properties using the keyword “this”.
1 2 3 4 5 6 | ngOnInit() { console.log((this as any).value1); console.log((this as any).value2); } |
Decorator with Arguments
To Create a Decorator
with arguments, we need to create a factory function, which returns the Decorator
function. You can refer to the StackBlitz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import { Component, VERSION } from '@angular/core'; @simpleDecorator({ value1: '100', value2: '200' }) @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { name = 'Angular ' + VERSION.major; constructor() { console.log('Hello from Class constructor'); } ngOnInit() { console.log((this as any).value1); console.log((this as any).value2); } } function simpleDecorator(args) { console.log(args); return function(target: any) { console.log('Hello from Decorator'); console.log(typeof target); console.log(target); Object.defineProperty(target.prototype, 'value1', { value: args.value1, writable: false }); Object.defineProperty(target.prototype, 'value2', { value: args.value2, writable: false }); }; } |
The simpleDecorator
takes the args
as argument and returns the decorator
function. The rest of the code is as same as above, except we use the args
to populate the properties.
1 2 3 4 5 6 | function simpleDecorator(args) { console.log(args); return function(target: any) { |
We apply the simpleDecorator
on the component as below
1 2 3 4 5 6 7 8 9 10 11 12 | @simpleDecorator({ value1: '100', value2: '200' }) @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { |
List of All Angular Decorators
Angular provides several built in Decorators. We can classify them under four different categories
- Class decorators.
- Property decorators
- Method decorators
- Parameter decorators
The following is a complete list of Decorators
in Angular.
Class Decorators
- @NgModule
- @Component
- @Injectable
- @Directive
- @Pipe
Property decorators
- @Input
- @Output
- @HostBinding
- @ContentChild
- @ContentChildren
- @ViewChild
- @ViewChildren
Method decorators
- @HostListener
Parameter decorators
- @Inject
- @Self
- @SkipSelf
- @Optional
- @Host
Class decorators
We apply class decorators to classes. @NgModule
, @Component
, @Injectable
, @Directive
& @Pipe
are Class Decorators in Angular
@NgModule
@NgModule Decorator defines the class as Angular Module and adds the required metadata to it.
1 2 3 4 5 6 7 8 9 10 11 12 | @NgModule({ providers?: Provider[], declarations?: Array<Type<any> | any[]>, imports?: Array<Type<any> | ModuleWithProviders<{}> | any[]>, exports?: Array<Type<any> | any[]>, bootstrap?: Array<Type<any> | any[]>, schemas?: Array<SchemaMetadata | any[]>, id?: string, jit?: true }) |
@Component
The Angular recognizes the class as Angular Component only if we decorate it with the @Component Decorator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Component({ changeDetection?: ChangeDetectionStrategy, viewProviders?: Provider[], moduleId?: string, templateUrl?: string, template?: string, styleUrls?: string[], styles?: string[], animations?: any[], encapsulation?: ViewEncapsulation, interpolation?: [string, string], preserveWhitespaces?: boolean, }) |
@Injectable
Injectable decorator has two purposes.
One it instructs the Angular that this class needs a dependency. The Angular compiler will generate the necessary metadata to create the class’s dependencies
Second, using the providedIn
we inform the Dependency Injection system how to provide the service.
1 2 3 4 5 | @Injectable({ providedIn?: Type<any> | 'root' | 'platform' | 'any' | null }) |
@Directive
@Directive Decorator marks a class as an Angular directive. The directives help us to change the appearance, behavior, or layout of a DOM element.
1 2 3 4 5 6 7 8 9 10 11 12 | @Directive({ selector?: string, inputs?: string[], outputs?: string[], providers?: Provider[], exportAs?: string, queries?: { [key: string]: any;}, host?: {[key: string]: string; }, jit?: true }) |
@Pipe
Decorator that marks a class as Angular Pipe and supplies configuration metadata.
1 2 3 4 5 6 | @Pipe({ name: string, pure?: boolean }) |
Property Decorators
Property Decorators are applied to the properties of the class.
@Input
Input
decorator marks the property as the input property. I.e it can receive data from the parent component. The parent component uses the property binding to bind it to a component property. Whenever the value in the parent component changes angular updates the value in the child component.
1 2 3 | Input(bindingPropertyName?: string) |
@Output
Output
decorates the property as the output property. We initialize it as an EventEmitter
. The child component raises the event and passes the data as the argument to the event. The parent component listens to events using event binding and reads the data.
1 2 3 | Output(bindingPropertyName?: string) |
@ContentChild & @ContentChildren
The ContentChild & ContentChildren are decorators, which we use to Query and get the reference to the Projected Content in the DOM. Projected content is the content that this component receives from a parent component.
1 2 3 4 5 6 | ContentChild( selector: string | Function | Type<any> | InjectionToken<unknown>, opts?: {read?: any; static?: boolean;} ) |
1 2 3 4 5 6 | ContentChildren( selector: string | Function | Type<any> | InjectionToken<unknown>, opts?: { descendants?: boolean; read?: any;} ) |
@ViewChild & @ViewChildren
The ViewChild
or ViewChildren
decorators are used to Query and get the reference of the DOM element in the Component. ViewChild
returns the first matching element and ViewChildren
returns all the matching elements as QueryList of items. We can use these references to manipulate element properties in the component.
1 2 3 4 5 6 7 | ViewChild( selector: string | Function | Type<any> | InjectionToken<unknown>, opts?: { read?: any; static?: boolean;} ) |
1 2 3 4 5 6 | ViewChildren( selector: string | Function | Type<any> | InjectionToken<unknown>, opts?: {read?: any;} ) |
@HostBinding
The HostBinding allows us to bind to a property of the host element. The host is an element on which we attach our component or directive. This feature allows us to manipulate the host styles
1 2 3 | @HostBinding(hostPropertyName?: string) |
Method decorators
Method Decorators are applied to the methods of the class.
@HostListener
The HostListener listens to host events. The host is an element on which we attach our component or directive. Using HostListener we can respond whenever the user performs some action on the host element.
1 2 3 | @HostListener(eventName: string, args?: string[]) |
Parameter decorators
Parameter Decorators are applied to the constructor parameter of the class.
@Inject
The @Inject()
is a constructor parameter decorator, which tells angular to Inject the parameter with the dependency provided in the given token. It is a manual way of injecting the dependency
1 2 3 | Inject(token:any) |
@Host
The @host is a Parameter decorator that tells the DI framework to resolve the dependency in the view by checking injectors of child elements, and stop when reaching the host element of the current component.
@Self
The @Self
decorator instructs Angular to look for the dependency only in the local injector. The local injector is the injector that is part of the current component or directive.
@SkipSelf
The @SkipSelf
decorator instructs Angular to look for the dependency in the Parent Injector and upwards.
@Optional
@Optional marks the dependency as Optional. If the dependency is not found, then it returns null
instead of throwing an error
Custom Decorators
You can also build your own custom decorators. You can refer to these articles.
Reference
- https://www.typescriptlang.org/docs/handbook/decorators.html#decorators
- https://angular.io/api?type=decorator
Read More
- Angular Tutorial
- Introduction to Angular Modules
- Angular Components Overview & Examples
- Injector, @Injectable & @Inject
- Directives in Angular
- Working with Angular Pipes
- Angular @input, @output & EventEmitter
- ContentChild and ContentChildren in Angular
- Understanding ViewChild, ViewChildren & Querylist in Angular
- @HostBinding and @HostListener in Angular
- @Self, @SkipSelf & @Optional Decorators Angular
- @Host Decorator in Angular