Best Practice Tip: Structural Directives

Repeating *ngIf is often a sign to use a structural directive.

Structural Directives in Angular is a powerful feature which is often underused in my opinion.
Let's try to change this and show you a repeating pattern which is better to solve with a structural directive.

The Problem

DRY violation with repeating *ngIf

Let's examine the following example:

import { ChangeDetectionStrategy, Component } from "@angular/core";
import { UserService } from './user.service';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-root",
  template: `
    <header>
      <span *ngIf="userService.user$ | async; let user">
        hello {{ user.firstName }} {{ user.lastName }}
      </span>
    </header>
  `
})
export class AppComponent {
  constructor(
    public userService: UserService
  ) {}
}

In the following example we have a user.service.ts that will hold our logged in user or null if the user is not logged in.
In the app.component.ts we are using the userService to display the user's name if the user is logged in.

A similar case was taken from a real world large project, where this kind of logic of checking if the user is logged in was repeated in many places, or in general not even checking if logged in but simple displaying data that we have on the logged in user.

If you have a repeating ngIf or a repeating need for some grabbing some data from a service and having that data available in component template, then you should consider using a structural directive.

The Solution

Let's create a structural directive that will handle the logic of checking if the user is logged in and if so, will display the template and pass the user to that template.

import { ChangeDetectionStrategy, Component } from "@angular/core";

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-root",
  template: `
    <header>
      <span *withUser="let user">
        hello {{ user.firstName }} {{ user.lastName }}
      </span>
    </header>
  `
})
export class AppComponent {}

Notice that we create a structural directive that will only render the template if we have a logged in user, the directive will also provide that user to the $implicit allowing the app.component.ts to use it like so:

<span *withUser="let user">
	hello {{ user.firstName }} {{ user.lastName }}
</span>

now every place I need the user I don't have to inject the user.service.ts and simply use my structural directive.
Handy isn't it? structural directives are an amazing shortcut to avoid repeating logic in your components.