Angular Decorators
Angular Decorators
Class Decorators
Angular offers us a few class decorators. These are the top-level
decorators that we use to express intent for classes. They allow us to
tell Angular that a particular class is a component, or module, for
example. And the decorator allows us to define this intent without
having to actually put any code inside the class.
A @Component and @NgModule decorator example with classes:
import { NgModule, Component } from '@angular/core';
@Component({
selector: 'example-component',
template: '<div>Woo a component!</div>',
})
export class ExampleComponent {
constructor() {
console.log('Hey I am a component!');
}
}
@NgModule({
imports: [],
declarations: [],
})
export class ExampleModule {
constructor() {
console.log('Hey I am a module!');
}
}
Property Decorators
These are probably the second most common decorators that you’ll
come across. They allow us to decorate specific properties within our
classes - an extremely powerful mechanism.
Let’s take a look at @Input(). Imagine that we have a property
within our class that we want to be an input binding.
@Component({
selector: 'example-component',
template: '<div>Woo a component!</div>'
})
export class ExampleComponent {
@Input()
exampleProperty: string;
}
We’d then pass the input binding via a component property binding:
<example-component
[exampleProperty]="exampleData">
</example-component>
The property decorator and “magic”
happens within the ExampleComponent definition.
In AngularJS 1.x (I’m going to use TypeScript here also, just to
declare a property on a class), we had a different mechanism
using scope or bindToController with Directives,
and bindings within the new component method:
const exampleComponent = {
bindings: {
exampleProperty: '<',
},
template: `
<div>Woo a component!</div>
`,
controller: class ExampleComponent {
exampleProperty: string;
$onInit() {
// access this.exampleProperty
}
},
};
angular.module('app').component('exampleComponent',
exampleComponent);
You can see above that we have two separate properties to maintain
should we expand, refactor or change our component’s API
- bindings and the property name inside the class. However, in
Angular there is a single property exampleProperty which is
decorated, which is easier to change, maintain and track as our
codebase grows.
Method Decorators
Method decorators are very similar to property decorators but are used
for methods instead. This let’s us decorate specific methods within
our class with functionality. A good example of this
is @HostListener. This allows us to tell Angular that when an event
on our host happens, we want the decorated method to be called with
the event.
Parameter Decorators
Parameter decorators are quite interesting. You may have come across
these when injecting primitives into a constructor, where you need to
manually tell Angular to inject a particular provider.
For a deep dig into Dependency Injection (DI),
tokens, @Inject and @Injectable, check out my previous article.
Parameter decorators allow us to decorate parameters in our class
constructors. An example of this is @Inject that lets us tell Angular
what we want that parameter to be initiated with:
import { Component, Inject } from '@angular/core';
import { MyService } from './my-service';
@Component({
selector: 'example-component',
template: 'Woo a component!'
})
export class ExampleComponent {
constructor(@Inject(MyService) myService) {
console.log(myService); // MyService
}
}
Due to the metadata that TypeScript exposes for us we don’t actually
have to do this for our providers. We can just allow TypeScript and
Angular to do the hard work for us by specifying the provider to be
injected as the parameter type:
import { Component } from '@angular/core';
import { MyService } from './my-service';
@Component({
selector: 'example-component',
template: 'Woo a component!'
})
export class ExampleComponent {
constructor(myService: MyService) {
console.log(myService); // MyService
}
}
Now that we’ve covered the types of decorators we can use, let’s dig
into what they actually are doing - and why we need them.