How to write a correct Angular Component

How to write a correct Angular Component

Besides all-known and common patterns about how to create a component in Angular, there're some advanced patterns not everyone would tell or show you — not because nobody knows about them, but maybe some developers keep them as secrets. ;)

Make sure you always "display" it right

Even if you might not find it useful, sometimes it can give you some big trouble.

You could be in a situation where can't understand why some Component's children or either the current Component – is not showing or positioned as it needs to be, due to this - you can spend a lot of time searching for the problem, in the end, to find out that a simple display: block can "save your life."

Just develop a behavior out of this, and always add :host { display: block; } in component styles. It's not mandatory to be block - this is just a typical case; change it as you need, but make sure you always apply it to your Component.

If you use ng to generate a component, there's a shortcut for that, add --displayBlock option in your command, it should look like this ng generate component YourComponent --displayBlock.

Add classes to host

This was previously named @Hostbind the class attribute which is not right (sorry for that guys). Using @Hostbinding('class') is not the right choice to add a class to the host, as it rewrites the already added classes outside the component/directive scope.

There's another solution I came up with, keep reading ;)

With Web Components coming in, why not think about the Angular Component that's a simple div or another common element?

Do you have to add the class names to children's components, or you can bind them to the host and save space in the Component's HTML?

Or at least to have the HTML cleaner? It would help if you thought about it.

I always do this whenever I have a parent element that holds all component HTML, for example, if this is the Component's HTML:

<div class="parent">
    <p>Lorem ipsum dolor</p>
</div>

Component's HTML example

I would rewrite it like this:

<p>Lorem ipsum dolor</p>

Component's HTML after rewriting the example

Thanks to the new Angular Directive composition API we can achieve this by injecting NgClass inside hostDirective.

Here's how it can be implemented:

@Component({
    selector: 'my-app',
    hostDirectives: [NgClass]
})
export class MyComponent implements OnInit {
    constructor(readonly ngClass: NgClass) {}
    
    ngOnInit() {
    	this.ngClass.klass = 'parent or-other-class';
    }
}

Add class names to host

In short, we tell Angular to add the NgClass directive to the host, and inside the component we inject it and send the class names to be used to the host.

Make sure .parent class is available outside of the component otherwise you won't see the .parent styles.

I probably should add more NgClass API explanation here, but this can make this article too big, so I might arrive with a new blog post clarifying NgClass and (why not) NgStyle in the future, keep an eye on me 👁️.

ChangeDetection to OnPush

Change detection is a cool feature in Angular, but you must be very attentive to it, as it can cause you significant issues. Why change it to OnPush? Simple, you don't need to recheck the Component's HTML every time something is changing inside the Parent Component.

But wait for a second, is it means Angular won't automatically check the Component's HTML for changes? Yes, it won't be. You must tell Angular when you should check the component changes, or use a straightforward trick — myVariable$ | async — let me explain to you more about it.

To mark the Component to be checked, a typical case is — to inject the ChangeDetectorRef class into the Component — ( I'm not going to show you how to achieve it here, check the official documentation page for more info. )

Another simple trick is to use Observables and Async pipe, remember I wrote an article about one of the best practices for sending HTTP requests in Angular – here's almost the same logic. Still, besides that, the async pipe automatically marks the Component to be checked for changes.

Let's see an example:

@Component({
  selector: 'my-component',
  templateUrl: './my-component.component.html',
  styles: [`
	:host { display: block }
  `],
  changeDetection: ChangeDetectionStrategy.OnPush,
  // See next section about exportAs metadata
  exportAs: 'myComponent'
})
export class MyComponent {
    myVariable$ = new BehaviorSubject('I hold a simple string')

	changeMyVariable() {
    	myVariable$.next('I\'m changed and automatically updated in template')
    }
}

Component's logic with Observables

<p>{{myVariable$ | async}}</p>

<!-- Change the variable & mark component to be checked for changes -->
<button (click)="changeMyVariable()">Change the variable</button>

Component's HTML with async pipe

Hope you got the idea!

Angular CLI allows to change it automatically: ng generate component YourComponent --changeDetection=OnPush

Make use of exportAs metadata

exportAs metadata is another option that makes the Component looks more than advanced. With it, we can get, set, and call the Component's functions/variables outside the Component's scope. Thanks to the Angular Team ;)

For example, let's say we have a simple component:

@Component({
  selector: 'my-count',
  template: `
    <p>Inside component scope: {{count$ | async}}</p>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  exportAs: 'myCount'
})
export class MyCountComponent {
  count$ = new BehaviorSubject(0);
  get count(): number {
    return this.count$.getValue()
  }

  inc(): void {
    this.count$.next(this.count + 1);
  }
}

MyCount Component logic

Now, let's try to increase the count outside the component scope:

<my-count #count="myCount"></my-count>
<p>Out of component scope: {{count.count}}</p>

<button (click)="count.inc()">Increase</button>

App Component Template

Check this StackBlitz for a better example. Pay attention, we haven't used Angular @ViewChild decorator to get the my-count Component instance, and we just added some simple logic ONLY inside the template – That's awesome!

Now, imagine what you can do with CdkPortals and exportAs metadata! – no worry, I might create another article about it later on ;)


Thanks and see you in the next article, I'll leave here another article you might be interested in.

4 Angular Tips for newbies
A personal opinion about how things should be done in Angular, especially for newbies. No tricky stuff, only simple recommendations.