How to use AngularJS Components with TypeScript?

If you are after a component-based application structure, AngularJS has a special kind of directive called Components that uses a simpler configuration and has some defaults. In this post, I’ll tell you how to use AngularJS Components with TypeScript to create a reusable component that will be responsible to show reviews for movies or restaurants and manage user ratings.

Writing a component-based application structure allow us to write an app in a way that’s similar to using Web Components or using Angular 2’s style of application architecture.

Advantages of Components

  • simpler configuration than plain directives

  • promote sane defaults and best practices

  • optimized for component-based architecture

  • writing component directives will make it easier to upgrade to Angular 2

When not to use Components

  • for directives that rely on DOM manipulation, adding event listeners etc, because the compile and link functions are unavailable

  • when you need advanced directive definition options like priority, terminal, multi-element

  • when you want a directive that is triggered by an attribute or CSS class, rather than an element

Scope

The scope of this post is to create a reusable reviews component that can show reviews and allows user feedback. This component should be able to display any kind of review, for e.g. movies or restaurants. The user-interface of this component looks like this:

Use AngularJS Components with TypeScript to write a reusable reviews component

Use AngularJS Components with TypeScript to write a reusable reviews component

Why use Components?

Practically, the above requirement is also possible using Angular Controller and Directive. Other than the advantages of components mentioned above a component allows us to use the best of both – controller and directive. I’ve realised that when using a component, we don’t miss anything and it covers most of the cases that one needs to write a simple or a business application. Read the points below to understand the code in this post properly.

What I like about Components?

  • To consume a controller, we now don’t need a linked route as a component can exist with or without a route and internally it uses controller, directive. So, this also removes usage of any data-ng-controller attributes.
  • It enforces developers to write controllerAs syntax which is one of the best practices to write controllers in AngularJS. By default, one can access the controller’s members using $ctrl in HTML template and also allows developers to name it something different like vm or model, etc.
  • It encapsulates information like HTML template to glue up with controller or directive, annotate dependencies for injection so that app is not broken when source files are minified.
  • It has some good defaults if compared to Directives. Directives can be used as an element or attribute with inherited or isolated scope. A component is quite simple that can be used as a custom element with isolated scope.
  • It also has a well-defined life-cycle discussed below.

Component’s life-cycle events

Each component can implement “life-cycle hooks”. Following are the methods that will be called at certain points in the life of the component:

  • $onInit(): this method is invoked after component’s controller is instantiated which separates instantiation and initialisation setup. Example, you may want to consume some services in controller at the time of initialisation and not instantiation.
  • $onDestroy(): this method is called when component’s controller is destroyed. Use this to release external resources, watches and event handlers.
  • $onChanges(changesObj): this method is called when input bindings change i.e. whenever one-way bindings are updated. The changesObjis a hash whose keys are the names of the bound properties that have changed and the values are an object of the form.
  • $postLink: this method is called when controller’s element and its children have been linked.

Make sure you have installed TypeScript for your IDE or code-editor and install AngularJS definition from DefinitelyTyped Repository in the form of Nuget or bower package – whatever you use. And need not to say, install AngularJS as well. The definition file provides strong typing and good intellisense support.

If you have read all the points above, let us start making a reusable reviews component. To use this component, we just want to define following in HTML template – inside body or featured section:

This looks neat and very similar to a directive. The end goal is to write this custom element and let Angular perform its magic. Let us now create app module:

Similar to other angular directives like ng-model or ng-click, for review-list we need to write a reviewList component. In code, the unique key needs to be in camel-case and in HTML template the usage should be with a hyphen before all upper-case alphabet. The definition for this component is defined in review-list.component.ts file as mentioned below:

Line no. 46 is the way to define a component which is same as defining a controller or directive. It requires a key to register a component and the definition. As such we are using TypeScript’s class to define component, we need to instantiate it at this step.

Thanks to the angular’s definition file, we have a class named ReviewListComponent on line no. 40 that implements ng.IComponentOptions that allows us to define a template, controller with controllerAs syntax. Even if we miss to give another name for controllerAs member, by default, all the controller’s members can be accessed via $ctrl in HTML template – e.g. $ctrl.reviews but with code above it will be model.reviews. The dependencies needed by controller is defined within the array and the last item in it is the controller class reference. Angular will instantiate this by itself which is same behaviour when writing a controller directly.

At line no. 7, we have ReviewListComponentController class that implements an interface. This interface defines all the members that controller must have. This class also uses $onInit() event hook to fetch reviews at the time of initialisation. Ideally service calls like this should be encapsulated inside a angular service for reusability, testing and maintenance reasons. To keep it simple, fetchReviews() just loads the JSON data in reviews.json file as mentioned below. As you can see, this data can be served from a service and can be a list of movies or restaurants. For this example, it is a list of restaurants with ratings.  The controller also defines two behaviours to up/down the ratings for a review.

The view is defined separately in review-list.component.html file that is mentioned below:

The component template above uses another component review-rating to show the stars or asterisks in the UI as shown in the image above. This component requires a value for its value binding where we pass rating from a review. As discussed above, components have isolated scope so all the values that it needs must be provided explicitly using component bindings.

The definition for reviewRating component is provided below which is quite similar to the definition above.

The class named ReviewRatingComponent uses transclude and bindings. Transclude is used so that the consumer of this component can define a custom UI markup and if nothing is provided then this component will use the default. The controller named ReviewRatingComponentController implements IReviewRatingComponentController interface that defines the members that controllers must have and it itself extends IReviewRatingComponentBindings interface that defines the bindings that a controller can access in this context i.e. value binding. Notice the < usage that denotes on-way bindings which are available since version 1.5.

This controller uses two component life-cycle event hooks: $onInit() is used to initialise the size of an entries array so that in linked HTML template, we can loop through this array to render stars or asterisks for UI. Without using the $onChanges() event, if a user up-vote or down-vote for a review, the underlying component will not be notified about any changes and a component works in isolated scope. So, as such we have only one member to monitor in this component, it just reinitialises the size of array and when it changes, the HTML markup is also updated.

The HTML template for this component is very simple. Note that track by $index is used with data-ng-repeat so that angular doesn’t complain about empty values in array as we are just concerned about its size for looping the exact number of stars.

<!– [Format Time: 0 try these out.0013 seconds] –>

This sums up my post that tells you how to use AngularJS components with TypeScript. I learnt more about this part of Angular with JavaScript using Scott Allen’s course. Let me know if you face any issues in the comments and I’ll try to help you. Learn more about Components using AnguarJS documentation. 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