Building an AngularJS Currency Converter

AngularJS is one of those hot new JavaScript frameworks that follows in the footsteps of Backbone to allow developers to easily write JavaScript intensive web applications.  AngularJS is gaining a lot of traction thanks to support from Google and a surplus of awesome features that enhance all aspects of JavaScript development.

I decided I would create a free currency converter using AngularJS as a way to gain familiarity with the basic concepts.  First I watched the Pluralsight course on AngularJS to gain familiarity with the core concepts.  This is not going to be a full blown intro to AngularJS, that requires a series of blog entries to do it justice.

Part 1: Laying out the application

For my layout I decided to go with Twitter Bootstrap just to make it look nice.  Screen shot below shows our interface:

image

To get AngularJS going, you need to first create a reference to the main framework library.  You can use the CDN available at http://www.angularjs.org and click on the download link.  Once you have that  you have to do some local setup.

The first thing is to register the Angular app.  Usually you create an app.js file, define the application, include it in your HTML page and then update your markup to make it aware of Angular.

app.js

'use strict';
// Declare app level module which depends on filters, and services
angular.module('currencyConvert', ['currency.controllers', 'currency.services']);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Index.cshtml
image

There are other files here, we will cover those shortly.  Finally, you need to make your page aware that Angular is being used.  This is nothing more than the addition of the ng-app directive.

<html ng-app="currencyConvert">

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

It is NOT a coincidence that the first parameter to module in app.js and the value given to ng-app is the same.  This is required to identify the Angular app in use for the web application.

The next angular concept to understand is that it enforces a strict separation of concerns.  All user interactions are handled, to start, in a controller.  I define my controllers in a controllers.js file

Each controller is then related to a block of HTML.  For example

<div ng-controller="currencyCtrl">
    <h3>Convert a Currency</h3>

    <form class="form-horizontal">
    

        <input type="button" class="btn btn-success" value="Convert" ng-click="convert()" /> 
        <input type="button" class="btn" value="Switch" ng-click="switch()" />
    </form>
</div>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

In this case, the currencyCtrl is in use here.  Note: the Ctrl suffix for controllers is a Angular convention, it is not required, but it is recommended that you stick with this convention to help other developers.  I left in a couple directive calls (both to ng-click), you can think of these as calling methods on the underlying view model, the viewmodel and controller are kind of one in the same in AngularJS.  Here is the controller definition:

'use strict';

/* Controllers */

angular.module('currency.controllers', []).
    controller('currencyCtrl', ['$scope', 'currencySvc', function ($scope, currencySvc) {
        currencySvc.getCurrencyCodes().then(function (data) {
            // ommited for brevity
        });

        $scope.convert = function () {
            // ommited for brevity
        };

        $scope.switch = function () {
            // ommited for brevity
        };
    }]);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Perhaps, the coolest thing Angular offers is Dependency Injection, you can see it in the example above.  Without going into too much detail, $scope and currencySvc are injected into the controller and subsequently used by the methods.  I am only showing the getCurrencyCodes call.  $scope is provided by AngularJS whereas currencySvc is a custom service which I defined.

To create your own custom service, similar to the controllers, you define them using angular.module call, but calling service instead of controller.  Here is the full code for the service interacting with my Currency Converter API:

'use strict';

/* Services */

angular.module('currency.services', []).
    service('currencySvc', ['$http', '$q', function($http, $q) {
        return {
            getCurrencyCodes: function() {
                var deffered = $q.defer();
                $http({ method: 'GET', url: '/Currency/List' }).
                    success(function (data, status, headers, config) {
                        deffered.resolve(data);
                    })
                    .error(function(data, status, headers, config) {
                        deffered.reject(status);
                    });

                return deffered.promise;
            },

            convert: function(srcCode, destCode, amount) {
                var deffered = $q.defer();
                var urlPath = "/Currency/Convert?srcCode=" + srcCode + "&destCode=" + destCode + "&amount=" + amount;

                $http({ method: 'GET', url: urlPath }).
                    success(function (data, status, headers, config) {
                        deffered.resolve(data);
                    })
                    .error(function(data, status, headers, config) {
                        deffered.reject(status);
                    });

                return deffered.promise;
            }
        };
    }]);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Understand that $q is a reference to Angular’s promise library.  If you are not aware what promises are, they are a paradigm used commonly to manage asynchronous calls.  More details are available here: http://docs.angularjs.org/api/ng.$q.  What is important to understand here is I am using the $http to contact my web service and get back JSON.  The results are then passed to the controller which then binds them to the view.

Creating the Currency Conversion API

This was actually rather difficult.  While there is a variety of Currency Conversion APIs available, finding one that was both complete and free proved challenging.  I ended up setting on Google, which actually provides an API for their calculator functionality which will return JSON.

Create the List of Currencies

I ended up having the screen scrape to get these values.  To make this task easier I added the HTML Agility Pack via nuget.  The URL to scrape was https://www.google.com/finance/converter.  You will notice that this isnt giving us a list of the currencies, instead I am scraping them out of the select list.

using (var client = new WebClient())
{
     var htmlString = client.DownloadString("https://www.google.com/finance/converter");
     var document = new HtmlDocument();
     document.LoadHtml(htmlString);

     var list = new List();
     var selectNode = document.DocumentNode.SelectSingleNode("//select");
     foreach (var optNode in selectNode.SelectNodes("option"))
     {
          list.Add(new Currency
          {
               Code = optNode.GetAttributeValue("value", string.Empty),
               Description = optNode.NextSibling.InnerText
           });
      }

      return list;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Using the HTML Agility Pack, the act of screen scrapping is made much easier than it would’ve been in the past.  This returns a JSON array of objects containing a code and description.  To populate our select lists we use the ng-options and ng-modal directives in AngularJS.  For example, here is the markup for the dropdown used to select the source currency:

<select ng-model="srcCode" ng-options="item.Code as item.Description for item in codes"></select>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

One thing I will point out is that for ng-options to work, the ng-modal attribute must also be present.  As you can tell, ng-options takes a query of sorts, which defines the mapping of value to display.  In this case we are saying that item.Code is the value (the value of the value attribute on each individual option tag) and item.Description is the value the user will actually see and “select”.  The presence of ng-model binds the srcCode property so that the controller can be aware of changes to its value.

Converting Currencies

Once we have our source and destination currency codes, we can attempt to convert them.  We will once again use an API call to front our call to Google.  But first we have to understand how we make that call.  Add a button to the markup and specify the ng-click attribute like so:

<input type="button" class="btn btn-success" value="Convert" ng-click="convert()" />

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The presence of this directive tells Angular to call the convert function on the related controller, passing no parameters, when the button is clicked (this could also be a link).  Here is the definition for the convert method as it exists within the controller:

$scope.convert = function () {
     currencySvc.convert($scope.srcCode, $scope.destCode, $scope.amount).
          then(function (data) {
                $scope.sourceDisplay = data.SourceDisplay;
                $scope.destinationDisplay = data.DestinationDisplay;
            });
        };

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This is the function that will get called when the user clicks the button.  All it does is pass the selected values from the Source Currency and Destination Currency (the Code values) and an amount entered through a textbox to the service call.  This type of pattern is known as MVVM (Model View ViewModel).  In this design pattern, we use binding to mitigate having to use JavaScript to get values out of controls. Very often the way values are extracted is through selection that is inherently dependant on certain definitions within the view.  Since these element may change it makes more sense to use binding to maintain functionality even in the fact of design changes.  This is quickly becoming the backbone for modern JavaScript development and also enables cleaner separation of code and markup, essential in JavaScript intensive applications.

When the function is called, it calls a method of the same name on the currency service (the same service we called to get the list of currency codes).  This method is responsible for actually contacting the API to perform the conversion, here is the code which makes the call:

          convert: function(srcCode, destCode, amount) {
                var deffered = $q.defer();
                var urlPath = "/Currency/Convert?srcCode=" +
                      srcCode + "&destCode=" + destCode + "&amount=" + amount;

                $http({ method: 'GET', url: urlPath }).
                    success(function (data, status, headers, config) {
                        deffered.resolve(data);
                    })
                    .error(function(data, status, headers, config) {
                        deffered.reject(status);
                    });

                return deffered.promise;
            }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This should look pretty similar to the service method above which we used to get the list of supported currency codes.  As for the code which does the conversion on the server, here it is:

public ActionResult Convert(string srcCode, string destCode, float amount)
{
     var client = new RestClient(string.Empty);
     var request = new RestRequest(
          string.Format("http://www.google.com/ig/calculator?hl=en&q={2}{0}=?{1}",
               srcCode, destCode, amount), Method.GET);

     var response = client.Execute(request);
     var content = response.Content;

     var jsonResponse = JObject.Parse(content);
     var returnObject = new ConvertResponse
     {
          SourceDisplay = jsonResponse["lhs"].ToString(),
          DestinationDisplay = jsonResponse["rhs"].ToString()
     };
}
return Json(returnObject, JsonRequestBehavior.AllowGet);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This time we make a call to Google’s calculator API, passing the source, destination, and the amount.  We then assign what we get back from Google (in JSON format) to an object and pass it back for display on the client.  Here is the code in the controller and view which is responsible for this:

// Controller (JavaScript)
$scope.sourceDisplay = data.SourceDisplay;
$scope.destinationDisplay = data.DestinationDisplay;

// HTML
{{sourceDisplay}} = {{destinationDisplay}}

This is the really neat thing about an MVVM type pattern is simply by updating the variable.  Angular is watching variables on $scope and ensuring that any changes made in the controller are reflected in the view.  This removes a lot of the monotonous code of reading and setting values that previously mucked up our code.

For your convenience the source code is available here: https://github.com/xximjasonxx/CurrencyConverter. In addition, you can see the application in action here: http://currencycovert.azurewebsites.net/

Advertisements

One thought on “Building an AngularJS Currency Converter

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s