Angular.js

AngularJS Components Library Example

In this article, we will take a look at developing a custom AngularJS Component. Then, we will learn to package it as a library so that we can reuse it across different projects. Firstly, we will start by getting familiar with the underlying concepts and their implementation leading up to writing our own Component library. Finally, we will consume the same in a sample component based application. So, let’s get started.

As part of this effort to explore components we will build a simple user registration component. We will then package the same as a library so that we can reuse this component across applications. The component will show a simple UI prompting for a username and password on a registration page. The component includes a password strength checker which will show compliance with a set of rules for a secure password.

1. Tools & Technologies

We will build a component and package it as a library as we learn about the topic. I have chosen the below set of tools and will use the following technologies as we work in this post. Although, feel free to use a different toolset as per your preference.

  1. NodeJS v6.3.0
  2. AngularJS v1.7.4
  3. Visual Studio Code IDE
  4. http-server v0.11.1

2. Project Structure

There are two separate folders as you can see in the below screen grab. One will host our custom component library and the other will host a sample application which will consume the component.

AngularJS Components Library - Project Folder Structure
Project Folder Structure

3. Introduction to AngularJS Components

Components were introduced with version 1.5 of AngularJS. They can be thought of as directives with templates. Apart from this they allow us to structure our app as a Component based one. Unlike directives which are applied to existing DOM elements to impart additional behavior. A component has its own HTML called its template. Let us take a look at how we define a Component.
A component resides in a js file with code that looks like below:

angular.
  module('moduleName').
  component('componentName', {
    template: 'Hello, {{$ctrl.user}}!',
    controller: function GreetUserController() {
      this.user = 'world';
    }
  });

We call the component method of an AngularJS Module and pass the name of the component as the first argument and an object called CDO or Component Description Object, which describes the component as the second argument. With templates for a Component we can either specify it inline by setting the value of template to a HTML snippet. Or we can also pass the URL of the HTML file containing the template by setting the templateUrl property.

4. Creating a Component

We will create a component which encapsulates functionality to render a user registration view. This component will also check for password strength and provide feedback to the user. We will wrap this piece into a library of its own so that we can easily share it among different applications with just a few steps.

Add the following files in a folder named similar after the component, i.e. user-registration-component.

  • package.json
  • user-registration.component.js
  • user-registration.template.html
  • user-registration.module.js
  • user-registration.style.css

The package.json file is needed to list the dependencies of our component library, version and name among other things. The content of the file are as below:

package.json

{
    "name": "user-registration-component",
    "version": "1.0.0",
    "description": "WCG -- AngularJS Component Library",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "http-server ./ -a localhost -p 8090 -c-1"
    },
    "keywords": [
        "AngularJS",
        "Component",
        "Library",
        "User",
        "Registration"
    ],
    "author": "Siddharth@WCG",
    "license": "ISC",
    "dependencies": {
        "angular": "^1.7.4",
        "bootstrap": "3.3.x"
    }
}

Now we create a file where we declare our module. This module will host our component as we will see later. The contents of this file user-registration.module.js is as below:

user-registration.module.js

'use strict';

angular.module('userRegistrationModule', []);

Moving on now we create our Component itself. The file, user-registration.component.js, has our component and it looks as below:

user-registration.component.js

'use strict';

angular.module('userRegistrationModule').
component('userRegistration',
{
    templateUrl: '/node_modules/user-registration-component/user-registration.template.html',
    controller: function () {
        var self = this;
        self.pwd = "";
        self.strength = '100%';
        self.score = 0;
        self.checkUpperCase = function () {
            for (var c = 0; c < self.pwd.length; c++) {
                if (self.pwd.charCodeAt() >= 65 && self.pwd.charCodeAt() <= 91) {
                    return 1;
                }
            }
            return 0;
        };

        self.checkEmpty = function () {
            var p = self.pwd || "";
            if (p.length > 0) {
                return 1;
            }
            return 0;
        };
        self.checkDigit = function () {
            var p = self.pwd || "";
            var digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
            var result = 0;
            digits.forEach(function(item) {
                if (p.includes(item)) {
                    result = 1;
                    return;
                }
            });
            return (result === 0 ? 0: 1);
        };
        self.checkLength = function () {
            var p = self.pwd || "";
            if (p.length >= 8) {
               return 1;
            }
            return 0;
        };
        self.checkSpecialChar = function () {
            var specChars = ['*', '@', '_', '.'];
            var p = self.pwd || "";
            var result = 0;
            specChars.forEach(function(item) {
                if (p.includes(item)) {
                    result = 1;
                    return;
                }
            });
            return (result === 0 ? 0: 1);
        };
        self.rules = [{
            ruleFn: self.checkEmpty,
            score: 0
        }, {
            ruleFn: self.checkDigit,
            score: 0
        }, {
            ruleFn: self.checkUpperCase,
            score: 0
        }, {
            ruleFn: self.checkSpecialChar,
            score: 0
        }, {
            ruleFn: self.checkLength,
            score: 0
        }];

        self.checkStrength = function () {
            self.score = 0;
            var runningTotal = 0;
            self.rules.forEach(function (item) {
                item.score = item.ruleFn();
                runningTotal += item.score;
                self.strength = (100 - ((runningTotal / self.rules.length) * 100)) + '%';
             }, self);
        };
    }
});

What we are doing here is declaring a component with template residing in a file called user-registration.template.html and a controller for this component. The template is described below and as for the controller it has code to check the strength of the password based on a set of rules. The rules are stored in an array of objects with each object having a function which evaluates the password and returns a score. The score is zero if the password fails the check otherwise it has a value of 1. We use the score from each function to evaluate the strength of the password and show it using a color scheme, with Red representing Weak password and Green representing a Strong password.
The process is triggered on the change event of the password field in the template.

The template of our component looks as below:

user-registration.template.html

<form>
    <div class="form-group">
        <label class="sr-only" for="inputUsername">Username</label>
        <input class="form-control" type="text" placeholder="Username" />
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-6 col-md-6">
            <div class="form-group">
                <input class="form-control" new-password type="password"
 ng-model="$ctrl.pwd" ng-change="$ctrl.checkStrength()" id="inputPassword" 
 placeholder="Password" />
            </div>
        </div>
        <div class="col-xs-12 col-sm-6 col-md-6">
            <div class="form-group">
                <input class="form-control" new-password type="password"
 id="inputConfirmPassword" placeholder="Confirm Password" />
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-6 col-md-6">
            <label>Password Strength</label>
            <div class="gradient">
                <div ng-style="{ 'width': $ctrl.strength }"></div>
            </div>
        </div>
    </div>
    <div>
        <ul>
            <li>Password cannot be empty</li>
            <li>Must contain atleast one Uppercase character</li>
            <li>Must contain atleast one number</li>
            <li>Must contain one of these characters * @ _ .</li>
            <li>Must be of 8 characters in length </li>
        </ul>
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-6 col-md-6">
            <div class="form-group">
                <button type="button" class="form-control btn btn-success">
                    Register
                </button>
            </div>
        </div>
    </div>
</form>

5. Publishing the Library

To reuse our component in other applications we need to publish it. We will use npm to achieve the same. We have a couple of options, either we publish our component as public or as a scoped package. The difference in the two being who is able to access the component. If we publish our component as public then everyone can access it. Otherwise we can go for scoped packages which limits the access to our component to our own organization. Let us look at the steps required to publish using both options. Before we begin using either option, we need to have an account with npmjs.org albeit one requires a paid account to publish scoped packages.

5.1 Publish with Public Access

To publish our component as a library with public access we need to follow the below steps
First, navigate to the directory containing the component and related artifacts that we want to publish.

>cd Component Library/user-registration-component

Then we need to login with npmjs.org credentials by using the following command.

>npm adduser

Afterwards we run the following command

>npm publish

This will publish our component library to npm and you can verify the same by visiting http://npmjs.org and searching by the name you gave your library.
To publish an updated version we need to update the version of our component in the package.json file in the directory of the component and follow the above steps again.

5.2 Publish with Restricted Access

To publish our component with private access we need to perform the below steps
Navigate to our component library directory

>cd Component Library/user-registration-component

Login with the npmjs.org account:

>npm adduser

Then run the below command:

>npm publish --access restricted

This should publish our component library with private access. We will take a look in the next section how to consume the same in another project.

6. Consuming our Library

Now that we are done publishing our component library let us take a look at how we can consume the same in an application. All the action would now be in the folder Demo Application. The Demo Application is setup as a simple AngularJS template with just a root app module and an index.html page. Now to pull down our published library and add it to this project we need to run the following command at the root of the project.

>npm install user-registration-module --save

This should pull down the latest version of our library and save it as a dependency in the package.json file of the project. The package.json file of our Demo Application should look like below:

AngularJS Components Library - Package.json File
Package.json File

Next we need to add the following script tags to our index.html page.

<script src="node_modules/user-registration-component/user-registration.module.js"></script>
<scriptsrc="node_modules/user-registration-component/user-registration.component.js"></script>

This will pull down our library for use. We need to add the userRegistrationModule as a dependency of the root module of our demo application in the app.module.js file as below:

'use strict';

angular.module('userRegistrationDemo', ['userRegistrationModule']);

All that we need to do now is add the following tag to our HTML file index.html.

<user-registration></user-registration>

The contents of the index.html file should look like below:

index.html

<!doctype html>
<html lang="en" ng-app="userRegistrationDemo">

    <head>
        <meta name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <meta charset="utf-8">
        <title>WCG -- Angularjs Component Library Demonstration</title>
        <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="app.css" />
        <script src="node_modules/angular/angular.js"></script>
        <script src="app.module.js"></script>
        <script src="node_modules/user-registration-component/user-registration.module.js">
        </script>
        <script src="node_modules/user-registration-component/user-registration.component.js">
        </script>
    </head>

    <body>
        <div class="container">
            <h3>WCG -- Angularjs Component Library Demonstration</h3>
        </div>
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <user-registration></user-registration>
                </div>
            </div>
        </div>
    </body>
</html>

To look at the results we will run the application using the following command

>npm start

Then we should navigate to the following URL in the browser http://localhost:8090. The browser would display the index page as below

AngularJS Components Library - Landing Page
Landing Page

As soon as you start typing in the password field you would see the strength checker provide feedback on the password. You should see something like below:

AngularJS Components Library - Landing Page Activity
Landing Page Activity

7. Download the Source Code

This wraps up how to create and publish an AngularJS Component Library.

Download
You can download the full source code of this example here: AngularJS Component Library

Siddharth Seth

Siddharth is a Software Development Professional with a Master degree in Computer Applications from IGNOU. He has over 14 years of experience. And currently focused on Software Architecture, Cloud Computing, JavaScript Frameworks for Client and Server, Business Intelligence.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button