Category Archives: JavaScript

AngularJS JavaScript

UTC dates handling in AngularJS applications

Almost every developer sooner or later is facing issues with dates. It may be formatting, timezones, etc. I would like to describe few tips about dates handling in AngularJS applications.

Using date filter

If you know, that some model field is native date object you can tell Angular to display it as date in UTC timezone. This is important, because in Javascript native dates are always in user’s local timezone. This is usually helpful when we need to display dates received from REST services, which most often are in UTC.

{{ ::model.someDate | date : 'dd/MM/yyyy' : 'UTC'}}

Using ngModelOptions

Using ngModelOptions is very helpful when you need to create input and allow users to set some date. The issue here is that when user enters date for the first time, everything is fine. But after storing it in backend, and receiving it back as date in UTC, you can have issues with differences between dates. In order to fix that Angular (from 1.3.0) has ng-model-options directive.

 <input
	id="someDate"
	name="someDate"
	type="date"
	ng-model="someDate"                            
	ng-model-options="{timezone: 'UTC'}">

Creating new date in UTC

New Date object created by new Date() will be in local timezone. If you want to create Date object in UTC timezone, you can use following service (it requires moment.js):

'use strict';

angular.module('dates').service('UtcDate', [
  function() {
    var UtcDate = function() {

    };

    UtcDate.prototype.getCurrentMomentUTC = function() {
      var date = new Date();
      return moment.utc(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    };

    return new UtcDate();
  }
]);
JavaScript

Announcing card.js

I would like to announce card.js!

It is brand new library with following features:

  • Credit card type detection based on IIN number. See more on wikipedia.
  • Credit card type detection for full length card number
  • Luhn algorithm validation. See more on wikipedia.

How to use it?

It can be loaded via a script tag in a HTML document for the browser (check examples/browser)

<script src='./relative/path/to/card.js'></script>

or as a CommonJS module.

For Node, put the card.js file into the same directory as the file that is requiring it and use

var card = require('./card.js');

or put it in a node_modules directory within the directory and use require(‘card.js’). See example in examples/nodejs.

The library is also available from the npm registry, so

$ npm install card.js

will install this library in a node_modules directory within the current directory.

Example of usage

card('4111111111111111').getType(); // output: visa
card('41').getIINType(); // output: visa
card('4111111111111111').isValid(); // output: true

Supported browsers:

  • Chrome
  • Firefox
  • Internet Explorer 9
  • Safari
  • Opera

Supported card types:

Issuing network card type returned by getType
Visa visa
Mastercard mastercard
American Express amex
Maestro meastro
Diners Club diners
Discover discover
JCB jcb
UATP uatp
InterPayment interpayment
InstaPayment instapayment
China UnionPay unionpay
Dankort dankort
AngularJS JavaScript

AngularJS: testing keydown listener

Working with AngularJS is really great experience. This framework comes with many handy features. One of them is build-in support for unit testing. In this post I want to show how to test keydown event listener.

I was recently working on performing some action when user press ESC key. Basically implementation is easy:

angular.module('app').directive('handleEsc', [
  '$document',
  function (
    $document
  ) {
    var ESC_KEY_CODE = 27;

    return {
      scope: {
        handleEsc: '&'
      },
      link: function (scope, element, attrs) {
        /**
         * Create handler for keydown event
         */
        function escHandler (event) {
          if (event.keyCode === ESC_KEY_CODE) {
            scope.handleEsc();
          }
        }

        /**
         * Attach handler to event
         */
        $document.on('keydown', escHandler);

        /**
         * Clean on destroy
         */
        scope.$on('$destroy', function () {
          $document.off('keydown', escHandler);
        });
      }
    };
  }
]);

So what this code is doing? First of all it creates isolated scope with binding method from parent scope by using &. Then in link function it is defining handler for keydown event and attaching this to document. In such cases it is necessary to unregister listener when in order to prevent memory leakage and this is done on scope destroy event.

Now lets move to the interesting part!

Testing keydown

I was looking for solution for a really long time. Finally my more experienced friends helped me.

'use strict';

describe('Directive: handleEsc', function() {
  var scope;
  var $compile;
  var $document;

  beforeEach(angular.mock.module('app'));

  var element = null;
  /**
   * Lets call scope.close() method on ESC key event
   */
  var template = '<div handle-esc="close()"></div>';

  beforeEach(inject(function($injector) {
    $compile  = $injector.get('$compile');
    scope     = $injector.get('$rootScope').$new();
    $document = $injector.get('$document');
  }));

  beforeEach(function() {
    element = $compile(template)(scope);
    /**
     * Create method and spyOn it.
     */
    scope.close = function() {};
    spyOn(scope, 'close');
  });

  function triggerEscKeyDown() {
    /**
     * Create KeyboardEvent
     */
    var e = new window.KeyboardEvent('keydown', {
      bubbles: true,
      cancelable: true,
      shiftKey: true
    });

    /**
     * Assing 27 as keyCode
     */
    delete e.keyCode;
    Object.defineProperty(e, 'keyCode', {'value': 27});

    $document[0].dispatchEvent(e);
  }

  it('should call callback function when the event happens', function() {
    triggerEscKeyDown();
    expect(scope.close).toHaveBeenCalled();
  });

  it('deregisters on scope $destroy', function() {
    scope.$destroy();
    triggerEscKeyDown();
    expect(scope.close).not.toHaveBeenCalled();
  });

});

As you can see in this test I had to use native KeyboardEvent in order to test my directive. As was not able to find any other working example with test for keydown listener. If you know other solution please share in comments.

JavaScript

JavaScript: private variable with prototype access

I was programming Java for over 6 years and I still sometimes think in object oriented fashion (you know: classes, static methods, interfaces, etc.). One of my recent problem to solve was to write an object with some private collection and public interface in JavaScript. So my first solution was like this:

var MyArray = function() {
	var array = [];
	this.add = function(item) {
		array.push(item);
	}
	this.getAll = function() {
		return array;
	}
}

var myArray = new MyArray();
myArray.add("some item");
console.log(myArray.getAll()); // ['some item']

That solution is perfectly fine is you need only couple of instances of this object. But memory usage is always my concern, so I wanted to make it better. In Java you don’t have to think about such issues, because you have classes. In JavaScript you have only objects and theirs prototypes. So maybe lets try to move methods add and getAll to prototype?

var MyArray = function() {
	var array = [];
	MyArray.prototype.add = function(item) {
		array.push(item);
	}
	MyArray.prototype.getAll = function() {
		return array;
	}
}

var myArray1 = new MyArray();
myArray1.add("some item 1");
console.log(myArray1.getAll()); // ['some item 1']

var myArray2 = new MyArray();
myArray2.add("some item 2");
console.log(myArray2.getAll()); // ['some item 2']
console.log(myArray1.getAll()); // ['some item 2'] - ERROR

As you see, this approach is wrong. Prototype will not work that way. Array in those methods is a reference to array created in last constructor call.

There are couple of options to solve this issue.

Use Safe Factory Pattern

Basically Safe Factory Pattern uses inner state variable to hold all references to objects used by prototype methods. Great description of this pattern can be found here: http://www.codeproject.com/Articles/133118/Safe-Factory-Pattern-Private-instance-state-in-Jav

There are also ready to use modules implementing this pattern:
https://github.com/dcleao/private-state/ – I didn’t use it, but if you did, please let me know in comments.

Use Safe Factory Pattern with implementation based on WeekMap

var MyArray = (function() {
  var refs = new WeakMap();

  var MyArray = function() {
    refs.set(this, []);
  };

  MyArray.prototype.add = function(val) {
    refs.get(this).push(val);
  };

  MyArray.prototype.getAll = function() {
    console.log(refs.get(this));
  };

  return MyArray;
})();

var myArray1 = new MyArray();
myArray1.add("some item 1");
console.log(myArray1.getAll()); // ['some item 1']

var myArray2 = new MyArray();
myArray2.add("some item 2");
console.log(myArray2.getAll()); // ['some item 2']
console.log(myArray1.getAll()); // ['some item 2'] - FINE!

Add methods as constructor function properties and bind them inside object

var MyArray = function() {
	var array = [];

	this.add = MyArray.add.bind(null, array);
	this.getAll = MyArray.getAll.bind(null, array);
}

MyArray.add = function(array, item) {
	array.push(item);
}
MyArray.getAll = function(array) {
	return array;
}

var myArray1 = new MyArray();
myArray1.add("some item 1");
console.log(myArray1.getAll()); // ['some item 1']
var myArray2 = new MyArray();
myArray2.add("some item 2");
console.log(myArray2.getAll()); // ['some item 2']
console.log(myArray1.getAll()); // ['some item 2'] - FINE!

This approach has small disadvantage, because for each instance of MyArray we need to bind both methods.

When I first encounter this issue I started to think that JavaScript is having problems in places, where you cannot imagine as for example Java developer used to having classes, static methods, etc. Lesson learned is that when working with other technology stack, we have to stop thinking with patterns and drop some habits.

What do you think all solution mentioned above? Which is the best? If you have any other, please let me know.