AngularJS 1.x with Typescript – 1

Everyone knows TypeScript especially after AngularJS team starts using Typescript to build AngularJS 2.0. I have been trying to avoid Typescript, since it is a transcompiler and the underlying language is still relevant and powerful. But over the holidays I spend some time learning Typescript with in the realm of AngularJS and found it interesting and easy to use. It reminds me of C# in many ways. With majority of developers are in Java or .Net world, because of Typescript, more people will be able to move to front end development easily.

When I was learning Angular first time, I wrote series blogs to educate myself and for anyone interested in following. So with that same spirit, I am going to do the same for AngularJS development with Typescript.

Couple of things;

  • This series is only for Angular 1.x not Angular 2.0
  • I am more interested in AngularJS so, I will not go deep into Typescript.
  • For development I am using Visual Studio Code. It is a free idea with good support to Typescript.
  • I use Win 10 desktop for development.
  • Instead of building a large application I will be focusing on concepts and sample example specific to concept.

 

Today we will setup our development environment and write a simple hello world program.

  1. Install Node/NPM

First and foremost, we need to install Node, even though we will not use node right away the npm tool that comes with Node we will use it to bring in the packages. So go to https://nodejs.org/en/ and download and install Node.

2. Install TypeScript

Open a command prompt and where ever you are, type in the following to install TypeScript.

npm install -g typescript

It doesn’t matter which directory you are in, since we are passing ‘-g’, TypeScript compiler will be available globally.

Once TypeScript installed, verify you have the latest version. by running following command

tsc -v

You should see version result as 1.7 or greater. If you have older version then you might have VS 2013/2015 installed and it already have old TypeScript in your path that you need to remove.

3. Install Visual Studio Code (Skip if you have a favorite editor)

Go to Visual Studio Code home page, download and install the editor.

4. Install TypeScript Definition Manager (TSD)

Before we start coding, we need to add intellisense to our editor. To do that, we need to install type script definition manager. Once TSD installed, similar to npm which can install the packages available under npm, we can use tsd to bring in the definition files of all javascript files we will use. For now think of it is a way to bring intellisense to the editor.

Fortunately TSD is available through npm so we install TSD once globally so we do not need to do it again and again like TSC.

npm install -g tsd

Once it is installed we will see how to bring the definition files during the development of the Hello World program.

 

Lets write some code:

On to developing Hello world program in AngularJS/TypeScript. Since we are using Visual Studio Code (VCS), I am going to open a command prompt and create a directory to build our hello world program.

I created a folder blog1 under c:\users\unni\learningangularts\.  Open VSC and use open folder option to point to the directory we created. It will create a empty editor with no files in it.

To do simple hello world program we need the following

index.html <- main html file

app.ts <- typescript file for module definition.

helloController.ts <- controller definition file.

tsconfig.json <- configuration file for type script.

scripts/angular.js <- angular js file from angular web site.

We will look at each one and discuss what is new with respect to TypeScript. Following is index.html

index

There is nothing new here except, I am using ‘controller as alias’.  All I am doing here is to render the message from the controller to the view through one way binding {{}}. There is not new here for type script as one would except.

If you notice closely, the script files referenced for app.js and helloController.js are java script files instead of type script files even though we will develop in type script files.

When I started out, I did have them as app.ts file instead of app.js. SO be mindful of that. When using TypeScript files (.ts extention), even though we develop using TypeScript at the end we transcompile them into javascript files so those are the files we need to reference in html files or anywhere.

Before we start adding working on controllers we need to two things

  1. First we need to bring in type script definition for angular.js so that, VSC can show intellisense. Before we do that, make sure you download angular.js file and drop it in some folder to distinguish them as framework script files. In my case, I created a script folder and dropped it in there.  With angular script file in place, open command prompt and run the following command at the root of the application directory, in our case @ “c:\users\unni\learningangularts\blog1

tsd install angular –resolve –overwrite –save

On running it should identify angular.js in the directory structure and bring in its type definition and also its dependencies. It seems angular.js still have dependency to jquery.js so it will bring the type definition of jquery as well. So you should expect to see something like the following

tsd

This should bring in the type definition for angular files and put them in typing folder.

2. Next we need to tell type script when it is transcompiling, when type of javascript should it create. In our case, we will try to create ES5 compliant javascript. It is done through creating “tsconfig.json

{
“compilerOptions”: {
“target”: “es5”
}
}

Now lets look at the type script magic.  Lets start with app.ts file.

angular.module(“helloWorld”, []);

Even though it is TypeScript file there is nothing type script about it. This is simple angular module definition as you would in normal angular app.

Next look at the hello controller;

//interface definition for model

interface IHelloWorldModel {
message: string;
}

//controller definition

class helloCtrl implements IHelloWorldModel{
message: string;

constructor(){
this.message = “Hello world!”;
}
}

//adding controller to angular module.

angular.module(“helloWorld”)
.controller(“helloCtrl”, helloCtrl);

When developing TypeScript files, it is recommended to create the interface for each controller, which need to be implemented so that view can get them. In other words, all the items in interface will be exposed in the view so by creating interface, the controller which implements forced to implement them.

In our example,  in index.html we are only displaying {{vm.message}} so we need only message in the interface. When defining the interface, make sure you specify the type also in there, which forces the controller to use the same type thus forcing strong type checking.

Next part is creating the controller itself. We use traditional class to define the controller than creating a function like you used to when created as javascript file. We make sure the controller implements the interface definition. In our case we need only message. So define it and in the constructor, pass a string to it.

At the end add the controller class to the module.It is very important, adding controller has to happen after the class definition.

One thing I forgot to mention to run the website through VSC we need a light weigh http server. Fortunately for us, there is one available through npm called http-server,  install it with npm like the following

npm install -g http-server

and then run it from the root directory of index.html file. This will start the server at specific port. once it is running without any errors,

httpserver.png

so far we have only created the TypeScript files, before we can run the code, we need to make sure we compile and generate the javascript file. Ctrl+Shift+B will build and generate the javascript file. But when you try to do this first time, vsc looks for a task file and since we did not create one, it will ask do you want to create one and acknowledge yes. It will create a task file.

Before we compile it, we need to make one quick change to that file. Open the tasks.json file under .vscode filer as shown in the picture below;

tasks

remove the HelloWorld from line 24 and make it empty as shown in the above pic. With all in place, perform compile (ctrl + shift + B), it should compile and generate the javascript files. If you look at the file structure to the left, you will see app.js next to app.ts and helloController.js next to helloController.ts.

With http-server running and all files generated, fire up a browser and go localhost:8080 should show hello world as shown below.

result

You can get the code from https://github.com/ksunair/learningangularts-blog1

I might have skipped over few things, if you have any questions, please let me know.

Happy Scripting…

Building your movie website with Movies DB in angularJS

I am a big fan of movies, for some time, I have been tinkering with building a website to see what is new on movies and TV. Recently I came across Movies DB website. The website by itself is wealth of information but the best part is, if you would sign up with them then you can use their rest services. You need to read the legal documents to see if it fits your bill also they throttle the requests coming in as well. I set out to write my own service so that I can use this service in my couple of other projects I am working on. Well, even that is already solved for me. Head out to lub-tmdb at GitHub, they have done most of the work for you already. So it is just a matter of hooking it into your project.

They have an excellent example project in their on how to use it. The example project is self contained, so I thought I add couple of lines to show, how to add into your existing project.

1. Download the min file from their build directory and put it in directory of your choosing. In my test code example, I put it in the root directory.

2. Add the script file to your index file, the real important thing is, it has to be added after your script with ‘angular.module’ definition. You would want to do the same if you build your own service.

<script src=”https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js”></script>
<script src=”app.js”></script>
<script src=”lub-tmdb.0.1.1.js”></script>

As you can see ‘lub-tmdb.0.1.1.js came adter my main app.js file.

3. I followed their example and created a simple search for a movie like the following in the index.html

<form ng-submit=”exec(‘search’, ‘movie’, query)”>
     <input type=”text” ng-model=”query”>
     <button type=”submit”>Search Movie</button>
</form>

<div>{{searchResults}}</div>

4. In the controller, again based on their example, I called the service as follows;

var app = angular.module(“main”, [‘lub-tmdb-api’])
     .value(‘lubTmdbApiKey’, ”);

var mainCtrl = function ($scope, lubTmdbApi) {

    var suc = function(result){
         $scope.searchResults = result.data;
     };

    var err = function (results) {
         $scope.searchResults = results;
     }

    $scope.exec = function (type, method, query) {
         lubTmdbApi[type][method]({
             query: query
         }).then(suc, err);
     }
};

app.controllers(“mainCtrl”, mainCtrl);

The important points in here are

  • Second line the above script, should have your api key that you got from the website.
  • Don’t convert it to JSON object in this line; $scope.searchResults = result.data;

I personally really enjoyed using both the angular service @ lub-tmdb and also the Movies DB. Both are solid and made my life little easier. Thanks a lot for both the services.

angular.js vs cujoJS

I have been using Angular for a while.Few of my friends strongly recommended me to look at the cujoJS. I would never say I am good at Angular, I am still learning and long way to go. On the other hand, I have no idea how cujoJS works. Only exposure I have with respect to cujoJS is that I sat in a presentation. So as you can see I am in no way to make the decision on one over other that quick. I am planning to use my blog site to go over simple example and compare and contract each on of them from these two framework perspective. Now comes the other question why cujoJS why not ember or knockout. Unfortunately, I never spend much on that either. I started using Angular and I was hooked. As a Silverlight programmer I found it so easy to transition into Angular world than the other two. If any of you have any comments on comparing those three or any other frameworks, let me know, I am happy to add them to my list as I start work on cujoJS.

Angular.js and cujoJS both are SPA development framework. One of the main difference I see when I look at both the framework, Angular JS is all encompassing (IoC, Binding, etc.,) framework. I know that is not fully true. In Angular you can use other libraries as well. But compare to cujoJS, Angular looks like it is trying to do lot more things internally while in cujoJS each one has its own JavaScript library. What it means is that, if I don’t like how the binding is done, I could replace cola with something else, well I don’t know if there is another one, but the bottom line is that, these important components are separated out. So you are not married to one huge framework. Component models has its own pros and cons but pros outweigh cons so in that perspective, I think cujoJS implementation is better. That is been said, when you are working in enterprise development, there are couple of important things we need think about, we will have varying level of expertise in the team and we need to make sure, we use less number of components in the development tools set from that aspect Angular is better but then again, it is not a big win for Angular though.

Please disagree with me and I learn from you as well.

  angular.js cujoJS
Component Model   X

Testing in Angular World

 

This has been a hot topic for me lately. I covered testing AngularJS in couple of blogs but over the time I noticed people who are coming from .Net world who are not used to TDD model still fall back to the old style development that is without tests or tests have been added after the fact. I think, either of the approach is totally wrong. Testing is first class citizens in AngularJS and we should treat them that way. I want to go over couple of argument I got when I asked them about why there are no tests or not following TDD and lets discuss about it. I will try to answer the best of ability.

We are still learning AngularJS so I can’t write unit tests.

Ok it seems very valid point. I would strongly recommend understand and learn how to do tests first. Testing in Angular is simple and straight forward. I am going to focus on testing in the coming blogs. Angular support both unit testing and end to end testing (e2e) testing. It is easy to learn and get going fast. First understand AngularJS concepts like $scope, $http and others then learn how to mock them, the rest is nothing but writing simple tests. The bottom line, if you are trying to learn AngularJS, learn testing along with basic concepts and then go into the details of AngularJS features.

Now going back point made, if you want to do something and you do not know how to do it in AngularJS then you can not write test for it. Well that is not 100% true. If you are following TDD model, then once you get the requirement that you are trying write code for, you are suppose to write the test first. Now that you already know how to write test, go ahead and write the test first and then try to do the implementation. When you are trying to implement, you may run into problems, then modify the tests as you make progress to fit the model you are writing. This is true in end to end testing as well (e2e), you might have end to end test against a form and as you learn you realize that you need data table, change the e2e test for it. But write the test first. It will help. Again, with the tests, even when you are learning, it catch the unexpected errors that you might make when experimenting with new concepts.

We can’t write tests because there is no logic in the code.

Excellent point, AngularJS is used to develop client side code. So if you are developing application properly, client side should be as dumb as possible. So in theory, we will have MVC pattern applied to both client side and server side. So all the complex business logic will be in the server side controller. Since you do not have complicated logic at client side, client side code should be very simple. Normally when we start out the client side code will be very simple, we might make a webapi call to get some data, bind them to the variables and that is it. So for that we do not need any tests. Trust me when I say this, that is how all the projects start. Always they are very simple in the beginning and as project start to grow, you will have more complex logic in it and at that time, it will be difficult to add test to it.

In the above scenario, my suggestion is to add unit tests to all the functions you might add to client side code, even if it is single line assignment statement. You will also agree, it is easy to write test cases of single line assignment statement, so go ahead and add the tests for it. It might seem silly, but now when you run the test, you have code coverage for the functions you have written. The benefit comes in the next iteration you are asked to add some logic to that method with simple assignment. You already have tests so you know why that function exists to start with and with that understanding you can add more tests to support new functionality without breaking the old ones. In this case, you are trying to understand what that function suppose to do since you might not have written the code, so you do not know what it was suppose to do. With tests, it is easy to see the scenarios and understand what exactly those methods suppose to do. It gives the confidence in your change you are making.

AngularJS provides not only unit testing, it also gives e2e testing. So even if there are no logic in the client side, you are working with the data coming from server to display data. So you can write tests for it. Write your e2e test with mock data and verify if the UI elements display the data as it suppose to be. The cases where the developer thinks there is no logic in the client side, then you will have more e2e tests than unit tests.

Angular JS – 10 (End to End Testing – Karma)

In the previous blog we looked at what is need to build a end to end test and run those test manually. In this blog, we will see how we can run this automatically in the background. The good thing is, there is nothing special end to end testing rather how you run it. Hopefully you got something from my previous blog on how to write an end to end test.

If you haven’t gotten the Intro to Karma project from GitHub, please do get it. It has the sample code and everything needed to run automated end to end test. Couple of things you need to run end to end test using Karma. You need a web server so in our case we will be using ‘node’. If you do not have it, please install it. Once you have node, you need to install Karma. Now that we have the sample code and required components like node and Karma, lets see how we can run Karma to test end to end tests.

To run karma, one would need a configuration file. Now if you got the introduction to karma project  from the GitHub then it comes with a simple configuration file. We will use that to run the end to end test. So lets first run the test with the configuration file already in the project. It is a two step process to do automated end to end tests.

  • Start the node server. Navigate to the location of the project. From the root directory, in DOS/terminal

node test\scripts\web-server.js

  • Now that node is running, lets run the Karma in another DOS/terminal from the root location of the project

karma start config\karma-e2e.conf.js

After the two steps, the test should run only once, it will not wait for code change and keep running the tests. We will modify that little later.

image

If you notice, we run Karma pointing to Karma.e2e.conf.js. Lets look at the configuration file.

1 basePath = '../'; 2 3 files = [ 4 ANGULAR_SCENARIO, 5 ANGULAR_SCENARIO_ADAPTER, 6 'test/e2e/**/*.js' 7 ]; 8 9 autoWatch = false; 10 11 browsers = ['Chrome']; 12 13 singleRun = true; 14 15 proxies = { 16 '/': 'http://localhost:8000/' 17 }; 18 19 junitReporter = { 20 outputFile: 'test_out/e2e.xml', 21 suite: 'e2e' 22 }; 23

The complete documentation of the configuration file can be found in the Karma documentation. Lets look at this simple configuration file.

Line 1: This is to set the base path for all the file references. I always like to make the base path to the root of the project. In this case, the karma configuration file is sitting @ config folder under the root folder so we will change one directory to the root directory.

Line 3-7: specifies what are the files to use for running the tests, Line 3-5 are default values. Line 6 specifies where is the end to end test.

Line 9: This option specifies, if you want to continue watch the files for any changes. In our case it is ‘false’, which means, it will run only once and it will not continue watching for any changes.

Line 11: Which browsers will be used for end to end tests.

Line 13:  This one is critical. This option specifies, do you want to run the test only once or run once and run and wait for changes the run automatically. So to run the end to end test automatically in the background as you are developing is by setting this ‘false’ and also Line 9 and set the value to ‘true’.

Angular JS – 9 (End to End Testing – manual)

Continuing from the previous blog, lets look at end to end testing. Based on what you have seen so far, it is very obvious without telling, how easy it to test Angular JS. The true separation of view and controller lend itself to test controller very easily. Everything is injectable which makes everything mockable in Angular JS. Now that we know, we can test controller with ease with Jasmine and Karma. Lets look at the other cool testing we can do in Angular, which is End To End test.

Angular End to End test allows the developer to do UI testing. This allows developer to enter values directly in the DOM elements and perform operations and then validate the results. This have been a difficult task so far with other client technologies and Angular JS made it easy for us. These end to end tests are called scenario tests. Angular follows Jasmine model of writing tests for end to end test as well.

If you have not already downloaded the Intro to Karma from Github, please download and we will use the same code to go over the end to end test.

There are two ways one could run end to end test. The first approach is to create your test and run the test manually and verify if the tests are passing. The second approach is to have the test run automatically in the background all the time while you developing your application and writing the tests. With this approach there is no need to run the test every time one would make a change to the code or tests. We will review the first approach in this blog.

Manual Test:

First lets look at the test we are going to write. Our application is very simple, it takes two numbers, multiplies and show the result on the screen as shown below

image

Since we are doing the UI testing, lets see the view under test.

1 <table> 2 <tr><td>First Number</td><td><input type="text" ng-model='firstNumber'/></td></tr> 3 <tr><td>Second Number</td><td><input type="text" ng-model='secondNumber'/></td> 4 <td><button ng-click='Multiply(firstNumber, secondNumber)'>Multiply</button></td> 5 ><td><input type="text" ng-model='decimals'/></td></tr> 6 <tr><td>Result</td><td>{{result | number: decimals}}</td></tr> 7 </table>

The two input fields are bound to ‘firstNumber’ and ‘secondNumber’, so in our test, we need to enter values for those two fields. Then find the button and click the button. Which would then perform the multiplication and save the result to ‘result’. So to confirm our UI code worked properly, we need to verify if ‘result’ contains the expected result. With this knowledge lets look at the test. The end to end test is available under test\e2e\mainscenario.js

As I mentioned before, end to end test also borrowed testing pattern from jasmine where we describe what we are testing and before each test and after each test, one could perform some task. All tests where marked by ‘it’. So going back to the test we were going to do;

1 it('should multiply two numbers', function(){ 2 input('firstNumber').enter(2); 3 input('secondNumber').enter(2); 4 element(':button').click(); 5 expect(binding('result')).toEqual('4.00'); 6 });

Line 1: starts the test with ‘it’, followed by two parameters, first one is the description of the test, followed by the test itself.

Line 2: Find the input for ‘firstNumber’ and enter value ‘2’.

Line 3: Find the input for ‘secondNumber’ and enter value ‘2’.

Line 4: Find the only button and click the button to perform multiplication.

Line 5: Find the ‘result’ and verify the result is ‘4.00’. Even though when we multiply 2 * 2 is 4, by default the decimal digit is set to 2 and result ‘4’ is send to number filter so the result becomes ‘4.00’.

When we do end to end test, we are testing the html page, so before each test, we need to make sure, the browser is pointing to the page under test. To do that, one need to define the beforeEach or at the start of each test. In our case, we define a beforeEach to route to the index.html as shown below

1 beforeEach(function(){ 2 browser().navigateTo('../../app/index.html'); 3 });

Line 2: has ‘../../app/index.html’. This is very important. To run, end to end test, one need to run the a web server first. Since I will be using node and the web server script is at test/script, it is very important you run the web server first from this location as follows

node test\scripts\web-server.js

now if you follow the line (2), what we are doing is, trying to find index.html from app folder two directories up from web-server.js location. That’s why we have the navigation. If web-server.js placed in root directory, then our navigateto would be ‘app/index.html’.

With node server is running, we need to create a html file to run our end to end script. It will be very simple script, we need to point to angular-scenario.js script and also our end to end script that’s all about it. So here is our runner.html file

1 <!doctype html> 2 <!-- to run e2e make sure you are running your web server --> 3 <!-- in our example we run node test/scripts/web-server .js --> 4 <!-- also open browser and point to http://localhost:8000/test/runner.html --> 5 <!-- we need to make sure we run node same way when we run the e2e test in command line as well --> 6 <html lang="en"> 7 <head> 8 <title>End2end Test Runner</title> 9 <script src="lib/angular-scenario.js" ng-autotest></script> 10 <script src="e2e/mainscenario.js"></script> 11 </head> 12 <body> 13 </body> 14 </html>

Please read step 2-5 in the html file to make sure everything is setup.

Now launch Chrome and point to the url in line 4 and that is it. You will have your end to end test run.

image

If you get the above screen then you are all set. In case if you run into problem, then you might not have one or more of the following not setup properly as mentioned in ng-model website. Also please try with Chrome do not try with IE.

Silverlight to Angular – 7 (Directives – I)

Even though I have Silverlight in the blog heading, we part ways with Silverlight in the last blog. Now, we are in Angular world. Ask any of the Angular user, which is their favorite feature in Angular? 99% of them will say, ‘Directives’. Without doubt, it is one of my favorite feature as well. In the beginning, when we started out with Angular, I mentioned that Angular can teach static HTML some new tricks like new elements, attributes etc., and it is done with Directives. It is without doubt that sets Angular apart from all the frameworks or toolsets.

I was going to create a step by step instruction for Hello Word directive but John Lindquist beat me to it. So instead of me doing ‘Hello World’, we will look at creating a directive for addition example we have been doing in couple of our examples. I am planning on doing it in three parts.

  1. Create a simple directive which shows static content.
  2. Create a simple directive which accepts input from HTML.
  3. Create a directive with binding and control hook up.

Lets start out by looking at our existing example;

View:

1 <!DOCTYPE html> 2 <html ng-app> 3 <head> 4 <title></title> 5 </head> 6 <body> 7 <div ng-controller="additionCtrl"> 8 First Number: <input ng-model="NumberOne"/><br/> 9 Second Number: <input ng-model="NumberTwo"/> 10 <button ng-click="add(NumberOne, NumberTwo)">Add</button><br/> 11 Result: {{Result}} 12 </div> 13 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script> 14 <script src="Scripts/additionCtrl.js"></script> 15 </body> 16 </html>

Controller:

1 function additionCtrl($scope) { 2 $scope.NumberOne = 0; 3 $scope.NumberTwo = 0; 4 $scope.Result = 0; 5 $scope.add = function (a, b) { 6 $scope.Result = Number(a) + Number(b); 7 }; 8 }

In the current code, there are no directives, it nothing but our simple addition program. We are going to first modify our code to create a directive, similar to ‘Hello Word’ . This will be new directive which will create a new HTML element, which will display ‘First Number’. Similar to Filters, we will create directive at module level. Lets start by creating a simple directive;

Problem: Create a new HTML element, which will display ‘First Number’. Call the new element as ‘display-number’.

Lets start with the test so we know what are we trying to do and also learn the TDD along the way. I am still not very good at Javascript so I might be not be following some standard pattern, which I hope someone will help me correct.

Test:

Following our previous unit test model, we will create two folders, one for App and another one for Test so that we can separate the code that goes into production. We will copy the SpecRunner.html from our previous test project and which is similar to the following

1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 <html> 4 <head> 5 <title>Jasmine Spec Runner</title> 6 7 <link rel="shortcut icon" type="image/png" href="http://searls.github.com/jasmine-all/jasmine_favicon.png"> 8 <link rel="stylesheet" type="text/css" href="C:\temp\jasmine\lib\jasmine-1.3.1\jasmine.css"> 9 <script type="text/javascript" src="http://searls.github.com/jasmine-all/jasmine-all-min.js"></script> 10 <script type="text/javascript" src="https://github.com/akiellor/rhino-hax/blob/master/modules/jasmine-console-runner.coffee"></script> 11 12 <script type="text/javascript" src="http://code.angularjs.org/1.0.6/angular.js"></script> 13 <script type="text/javascript" src="http://code.angularjs.org/1.0.6/angular-mocks.js"></script> 14 15 <!-- include source files here... --> 16 <script type="text/javascript" src="../App/scripts/additionCtrl.js"></script> 17 18 <!-- include spec files here... --> 19 <script type="text/javascript" src="spec/displayNumber.spec.js"></script> 20 </head> 21 22 <body> 23 </body> 24 </html>

Line (8) – Jasmine downloaded location will have the css file.

Line (16) – points to our controller where we will do addition of  two numbers.

Line (19) – This is where we are going to put our test spec.

Following code is our displayNumber.spec.js

1 describe('displayNumber', function () { 2 var element, scope; 3 4 beforeEach(module("additionApp")); 5 6 beforeEach(inject(function($rootScope, $compile) { 7 element = angular.element('<display-number></display-number>'); 8 scope = $rootScope; 9 $compile(element)(scope); 10 scope.$digest(); 11 })); 12 13 it('should create displayNumber span element', function () { 14 var elem = element.find("span"); 15 expect(elem.length).toEqual(1); 16 }); 17 18 it('should create displayNumber span element with "First Number" as text', function () { 19 debugger; 20 var elem = element.find("span"); 21 expect(elem[0].childNodes[0].data).toEqual("First Number"); 22 }); 23 });

Line (4) – When testing directives, we will create an app and we load that every time before each test.

Line (6-11) are the ones required to generate the directive into HTML span element.

Line (6) – Will talk about compiling and linking little bit later, but for now, we inject rootScope and compile from angular mock to our test.

Line (7) – <display-number> is our directive under test. So we create an element with that directive as if it appears in the view.

Line (9) – Compile will walk through the HTML and create list of angular directives available.

Line (10) – $digest triggers the process converts the all the directives to proper HTML tag and generate associated watch etc.,

Line (13 – 16) is our first test to make sure there is span tag created after directive processed.

Line (18 – 22) is our second test, which make sure the text ‘First Number’ shows up in the Span.

If you would run, the specRunner.html, both the tests will fail.

View with the directive.

You can find the solution in jsFiddle.

1 <div ng-controller="additionCtrl"> 2 <display-number></display-number>: <input ng-model="NumberOne"/><br/> 3 Second Number: <input ng-model="NumberTwo"/> 4 <button ng-click="add(NumberOne, NumberTwo)">Add</button><br/> 5 Result: {{Result}} 6 </div>

Line (2), you will see a new HTML tag <display-number>, this is the part which makes Angular awesome. We literally created a new HTML tag for the purpose of our coding. Even though other frameworks allow you to do something similar, you can not create new HTML element like Angular does. Couple of things to remember;

  1. Make sure ng-app is there in the HTML tag pointing to app module.
  2. Always make sure, when you create an directive element, always put closing element. Don’t use inline closing like <display-number />

Here is the controller with directive

1 var app = angular.module("additionApp", []); 2 3 app.directive("displayNumber", function () { 4 return { 5 restrict: 'E', 6 template: '<span>First Number</span>' 7 }; 8 }); 9 10 function additionCtrl($scope) { 11 $scope.NumberOne = 0; 12 $scope.NumberTwo = 0; 13 $scope.Result = 0; 14 $scope.add = function (a, b) { 15 $scope.Result = Number(a) + Number(b); 16 }; 17 }

Line (1) when using directives, similar to Filters, you need to have an app associated with it.

Line (3) sets up the directive. If you notice the method name is ‘displayNumber’ (camel case). But when you use the directive you use display-number.

Line (4) there are couple of ways, you can create directives and we are following a simple approach where it return a class for directives.

Line (5) ‘restrict’ specifies, is the directive an ‘Element’ (E), Attribute inside an element (A), Class (C) or Command (M). In our case we are creating a new element called display-number so we are restricting it to an Element. The default is Attribute.

Line (6) provides the template that need to be used in place of the directive. In this case, it is nothing but straight forward span element.

Rest of the code is our old controller. Next we will look at how to pass in values to