How to write custom AngularJS Directive using TypeScript?

AngularJS framework has many powerful features, one of them is known as Directives. In this post, I’ll tell you how to write custom AngularJS Directive using TypeScript. In the beginning, I’ll tell some basics about directives but if you would like to directly see the TypeScript code, you may skip the basics.

What are Directives?

At a high level, directives are markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS’s HTML compiler ($compile) to attach a specified behaviour to that DOM element (e.g. via event listeners), or even to transform the DOM element and its children.

Angular comes with a set of these directives built-in, like ngBind, ngModel, and ngClass. Much like you create controllers and services, you can create your own directives for Angular to use. When Angular bootstraps your application, the HTML compiler traverses the DOM matching directives against the DOM elements.

AngularJS Documentation

Example

Look at the usage for ng-controller and ng-bind directives that are available out of the box in AngularJS framework.

Normalization Process

In the code snippet above, there are many ways to consume a directive. It is the job of AngularJS HTML compiler to determine which elements match which directives. It typically refer to directives by their case-sensitive camelCase normalized name (e.g. ngModel). However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case forms, typically using dash-delimited attributes on DOM elements (e.g. ng-model).

The normalization process is as follows:

  1. Strip x- and data- from the front of the element/attributes.
  2. Convert the :, -, or _ -delimited name to camelCase.

Best Practice

Prefer using the dash-delimited format (e.g. ng-bind for ngBind). If you want to use an HTML validating tool, you can instead use the data-prefixed version (e.g. data-ng-bind for ngBind). The other forms shown above are accepted for legacy reasons but we advise you to avoid them.

Types of Directives

The AngularJS HTML compiler i.e. $compiler can match directives based on element names, attributes, class names, as well as comments. Example below shows the various ways a directive named myDir can be referenced from within an HTML template:

Best Practice

Prefer using directives via tag name and attributes over comment and class names. Doing so generally makes it easier to determine what directives a given element matches.

Comment directives were commonly used in places where the DOM API limits the ability to create directives that spanned multiple elements (e.g. inside <table> elements). AngularJS 1.2 introduces ng-repeat-start and ng-repeat-end as a better solution to this problem. Developers are encouraged to use this over custom comment directives when possible.

Custom Directive in TypeScript

Let us create a directive where the only purpose is to add title, sub-title and text at the right, which altogether works as a header for any block or widget or tile. This is a good example as this can be reused at many places and can be defined as a directive with its own isolated scope as the information to present in each block needs to be dynamic.

Let us look at the HTML, typescript code below:

To leverage the features of TypeScript, an interface is created to defined the scope members that can be used within directive. As such we want to create an instance of our directive, we define a class that implements IDirective.

To get the typed definition, look at this amazing repository for any popular JavaScript library. These definitions allow us to get any compile time errors and good intellisense support in IDE. I use Visual Studio, Visual Code and both supports TypeScript very well.

This directive doesn’t need any built-in angular service or any other dependencies, so the $inject static member is just an empty array of string. If a dependency is listed, framework looks at this member and tries to inject it by, if found.

The constructor does nothing but we do have a static instance method that just creates an instance of this directive. The framework expects an instance of directive at the time of defining a directive using module’s directive API.

The scope member of the class is important here as this directive uses the isolated scope i.e. it’s own members that can be used in the directive’s template but doesn’t inherit the state of the outer/parent. For readability and maintenance, we use templateUrl member to give the source of template. Also, the restrict member sets the usage level to element and attribute only using E and A respectively.

The restrict option is typically set to:

  • ‘A’: only matches attribute name
  • ‘E’: only matches element name
  • ‘C’: only matches class name
  • ‘M’: only matches comment

These restrictions can all be combined as needed: ‘AEC’ matches either attribute or element or class name.

This directive can now be used as per snippet below:

This directive can be used at element or attribute level either with hardcoded or dynamic title, sub-title or right-text scope members. Notice that the latter on is normalized by the compiler in the same was as it is done for any directive. The snippet above is used inside a template that is linked with a controller that has a title, description and refreshed date-time information to show to the user. With some more markup and design, it looks like this below:

UI for AngularJS Directive in TypeScript

UI for AngularJS Directive in TypeScript

If you would like to learn more about how to integrate AngularJS and TypeScript, refer to my AngularJS posts. If you want to learn something specific then get in touch and I’ll write a post about it.

Siddharth Pandey

Siddharth Pandey is a Software Engineer with thorough hands-on commercial experience & exposure to building enterprise applications using Agile methodologies. Siddharth specializes in building, managing on-premise, cloud based real-time standard, single page web applications (SPAs). He has successfully delivered applications in health-care, finance, insurance, e-commerce sectors for major brands in the UK. Other than programming, he also has experience of managing teams, trainer, actively contributing to the IT community by sharing his knowledge using Stack Overflow, personal website & video tutorials.

You may also like...

Advertisment ad adsense adlogger