Stop Overloading Your Angular Components: Start Using Host Directives!
Tags: angular, beginners
Published: 2024-01-27 10:16:44

When we build Angular apps, sometimes our components do too much. Take an `AppComponent`, for instance, that's burdened with tasks like changing the page title, receiving app updates, logging the app version, and tracking user clicks. These functions, though important, don't align with the component's main role of displaying content. As a result, `AppComponent` becomes crowded and complex, deviating from its primary purpose. This is where Angular's directives help. They are a simple solution that makes it easier to handle these tasks.

Directives in Angular allow us to neatly separate these side tasks from the component's core functionalities. By assigning responsibilities like click tracking and logging to directives, we prevent the main component from becoming overwhelmed. This leads to a cleaner, more focused `AppComponent` that sticks to displaying and interacting with content. Directives keep our apps organized, making them simpler and easier to handle.

Example of a 'Do Everything Component':

```typescript

import { Component, OnInit, HostListener } from '@angular/core';
import { TitleService } from './title.service';
import { UpdateService } from './update.service';
import { VersionLoggerService } from './version-logger.service';
import { ClickTrackingService } from './click-tracking.service';

@Component({
  selector: 'app-root',
  template: `...`,
  // ...
})
export class AppComponent implements OnInit {
  constructor(
    // Ugh, so many injected services!
    private titleService: TitleService,
    private updateService: UpdateService,
    private versionLoggerService: VersionLoggerService,
    private clickTrackingService: ClickTrackingService
  ) {}

  ngOnInit() {
    // Updating the title
    this.titleService.updateTitle('App Title');

    // Subscribing to app updates
    this.updateService.getAppUpdates().subscribe(update => {
      // Handle update logic
    });

    // Logging the app version
    this.versionLoggerService.logVersion();

    // Other unrelated behaviors can also be added here
  }

  @HostListener('click', ['$event'])
  trackClick(event: Event) {
    this.clickTrackingService.trackClick(event);
  }
}

```

Now lets create some directives to help us move these extra jobs out of our component. We can make a special directive for each job, like one for changing the page title and another for tracking clicks. This keeps our components simple and focused on their main job.

```typescript
// update-title.directive.ts

import { Directive, OnInit } from '@angular/core';
import { TitleService } from './title.service';

@Directive({
  selector: '[updateTitle]',
})
export class UpdateTitleDirective implements OnInit {
  constructor(private titleService: TitleService) { }

  ngOnInit() {
    this.titleService.updateTitle('New Title');
  }

}

// click-track.directive.ts

import { Directive, HostListener } from '@angular/core';
import { ClickTrackingService } from './click-tracking.service';

@Directive({
  selector: '[appClickTrack]',
})
export class ClickTrackDirective {

  constructor(private clickTrackingService: ClickTrackingService) {}

  @HostListener('click', ['$event'])
  onHostClick(event: MouseEvent): void {
    this.clickTrackingService.trackClick(event);
  }
}

```

As you can see, each directive handles one job. This makes them easier to work with and check. For instance, the directive for changing the page title does just that. It keeps its job separate from the rest of the app's code.

Adding these directives to our components is easy. We use `hostDirectives` in the `@Component` part to put in our new directives. Now, `AppComponent` is more about showing content and less about doing many different jobs.

```typescript

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `...`,
  hostDirectives: [UpdateTitleDirective, AppUpdateAlertDirective, LogVersionDirective, ClickTrackDirective] // Put your host directives here!
})
export class AppComponent {
  // AppComponent focuses on its template-related logic only
}

```

In the end, using directives in Angular for tasks that don't deal with showing content is a really good idea. It makes our components simpler and less full of different tasks. Building and maintaining our app becomes easier. The components stay focused on their main job – showing things to users. Using directives this way keeps our app neat and easy to work with.