v19 launch sale ends in ... Get 25% off BUY NOW
3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 4

Understanding Decorators in Angular

STANDARD

Understanding Decorators in Angular

We’ve already been exposed to decorators a little bit. Specifically, we have seen @Component and @Directive decorators. A decorator in Angular looks like this:

@Component({
    someThing: 'some-value',
    someOtherThing: [Some, Other, Values]
})
export class SomeComponent {}

They definitely look a little weird — they are like little hats that sit on top of our classes — but they play an important role. Their role in an Angular application is to provide some metadata about the class you are defining, i.e. they talk about your class rather than define the class.

The concept of a decorator is not an Angular specific concept. This is a common design pattern in Object Oriented Programming. It isn’t necessary for us to discuss the general applicability of the decorator pattern, but let’s consider what this is achieving for Angular.

I think that a @Component decorator shows this quite well:

@Component({
  selector: 'my-component',
  template: `<p>Hello</p>`,
  styles: [
    `
      .some-class {
        display: none;
      }
    `
  ]
})
export class MyComponent {}

If you prefer to define your templates and styles in separate files you can do this instead:

@Component({
  selector: 'my-component',
  templateUrl: 'my-component.component.html',
  styleUrls: ['my-component.component.scss']
})
export class MyComponent {

}

We have the class itself which handles all of our logic for us, but that is not all Angular needs to know to create the component. Consider that we are able to add a component to the template of another component like this:

<my-component></my-component>

Angular needs to know what name to give that tag and that is what the selector property in the decorator allows us to do. We also need a template associated with our class, and the decorator allows us to do that with the template property (or the templateUrl property if you want to link out to a separate template file rather than defining it inline in the decorator). The same thing again with the styles property. In this case, this decorator is telling Angular that:

  • This class is a component (by virtue of the fact that we are using the @Component decorator)
  • It should have a selector of my-component
  • This is the template for the component (or this is where to find it)
  • This is the styles for this component (or this is where to find it)

With all of that extra information, Angular can do its job and create the component.

@Directive

We already know about the @Component decorator, now let’s cover all of the common decorators you will be using one at a time.

The @Directive decorator allows you to create your own custom directives. We’ve touched on the concept of a directive briefly, but basically, it allows you to attach some behaviour to a particular component/element. Typically, the decorator would look something like this:

@Directive({
    selector: '[my-selector]'
})

Then in your template, you could use that selector to trigger the behaviour of the directive you have created by adding it to an element:

<some-element my-selector></some-element>

We talked before about a directive that would make the background colour of an element red. Let’s take that a step further and create a directive that will change the background colour to a random colour.

I am going to create this directive for the home page component in the example app we have been working with. If your root component no longer displays your home component, I am going to leave it to you to figure out how to get that displaying correctly again.

Create a file at app/home/ui/random-color.directive.ts and add the following:

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

@Directive({
  selector: '[randomColor]',
})
export class RandomColor {
  @HostBinding('style.backgroundColor') color = `#${Math.floor(
    Math.random() * 16777215
  ).toString(16)}`;
}

NOTE: This is a sneaky little technique to create a random colour in JavaScript. I definitely did not come up with this, I stole it from here.

I am sneaking in an Angular feature here that we haven’t talked about yet. The idea with a HostBinding is that it binds to the host which means the element/component that the directive is attached to (remember the comparison I made about the directive being like a parasite, well that analogy holds here because a parasite attaches to a host). We can use this host binding to change some property of the host.

We have made this directive standalone so we do not need to worry about an @NgModule. However, just so that you are somewhat familiar with the NgModule approach… if you were using modules and wanted to use this directive in a component, it would need to be declared within the same module as that component, for example:

IMPORTANT: Do not do this — we are using a standalone directive, this is just to show you what the module option might look like.

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { RandomColor } from './home/ui/random-color.directive';
import { WelcomeComponent } from './home/ui/welcome.component';
import { SettingsComponent } from './settings/settings.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    SettingsComponent,
    WelcomeComponent,
    RandomColor,
  ],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

This would then allow us to use the directive within the HomeComponent. But, since we are using a standalone directive we can just add it to the imports of our standalone component:

import { Component } from '@angular/core';
import { RandomColor } from './ui/random-color.directive';
import { WelcomeComponent } from './ui/welcome.component';

@Component({
  selector: 'app-home',
  template: `
    <app-welcome />
    <p>I am the home component</p>
    <p randomColor>I am stylish</p>
  `,
  imports: [WelcomeComponent, RandomColor],
})
export class HomeComponent {}
STANDARD
Key

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).