Understanding Angular Structural Directives

Tomasz Kula
Netanel Basal
Published in
5 min readJun 25, 2018

--

In this article, we’ll create a carousel component with the use of custom structural directive. We’ll explore micro-syntax offered by Angular to create a clean domain-specific language to describe the directive inputs.

The consumer of the directive will be able to use it like this:

The article assumes the basic knowledge about structural directives. If you haven’t created a structural directive before or you need to refresh your knowledge, check out this section of the official docs.

Template Directives Micro Syntax

  • *carousel is the directive name. The * signals that we are dealing with a structural directive. Angular de-sugars this notation into <ng-template> that surrounds the host element and its descendants.
  • The let keyword declares a template variable that you reference within the template.
  • from is a binding key. You can name it however you like. Here we named it from to create a nice readable string image from images.
  • images is the value we want to pass into the directive.

Angular will combine the name of the directive (carousel) with the binding key (from) and create a binding to an Input. That means that inside the directive we can refer to images as @Input() carouselFrom.

Domain Specific Language ( DSL )

You can get very expressive with the domain specific language that you want to create inside your template directive. You aren’t limited to a single binding key. Let’s add two additional inputs for controlling the carousel auto-play behavior.

The Context Object

When we create the embedded view, we can pass in the context object. It contains all properties that we want to make available for binding in the template.

We don’t know the variable name the user is going to pick while binding in the template. The user can say let image, let img or even let item. There is a special property on the context object called $implicit. When the user says let anyVariableName, it actually binds it to the value specified under the $implicit key.

That means that this:

<div *carousel="let image">

is equal to:

<div *carousel="let image = $implicit">

Any other value must be explicitly named in the context object and referenced by that name in the HTML binding. In the carousel directive, we’ll expose the controller object that will allow users to change the currently displayed image.

<div *carousel="let image; let ctrl = controller"></div>

The Implementation

Now that we understand the micro-syntax and the context object, we have all the tools that we need to implement the carousel directive.

As with most structural directives, we inject the TemplateRef and use it to create the embedded view on the injected ViewContainerRef. For now, we set context.implicit$ to the first image of the images @Input property.

At this point, the carousel will always display the first image, as we have not yet implemented the controller object.

Next, we extend the TemplateRef context with the controller object. It implements the next and prev methods that must be invoked by the carousel’s consumer in order to change the currently displayed image.

In the HTML template, we can access the controller by binding it to a template variable.

Auto-play

Now that we have the basic functionality down, we can enhance the directive with auto-play behavior.

First, we create the carouselAutoplay @Input. If the auto-play is set to on, we create a timer that will periodically advance the carousel. Otherwise, we clear the timer. To avoid memory leaks, we also clear the timer when the carousel component is destroyed.

Finally, we add the carouselAutoplay @Input to allow carousel’s consumers to set the auto-play delay value. We set the default auto-play delay to 1 second.

Structural Directive or Component?

The main benefit of using structural directive is the flexibility it provides.

The structural directive doesn’t make any assumptions about the way the consumer will style, animate, or display its elements.

You have direct access to:

  • The directive’s host element,
  • The directive’s child elements (image and controller buttons).

That means that you can easily place alt or title attributes on the image element. You can also enhance the image element with another directive not related to the carousel.

You are free to position the next and previous buttons however you like. You can even decide to hide the buttons and have an auto-play only carousel (please don’t do that).

As a proof of concept, here are a few variations of carousel components that can be created with the use of the carousel directive.

  1. Auto-play only carousel

2. Carousel with navigation buttons

3. Carousel with image descriptions

You can find the source code for the carousel directive and each of the carousel components in the links below:

This article is heavily inspired by this excellent talk given by Alex Rickabaugh at the Angular Mix.

If you like the content, please clap 👏👏👏

To read more about Angular, follow me on Medium or Twitter.

--

--