Tag Archives: JavaScript

ECMAScript ES6 (ES2015) changes overview

I’ve been playing recently with ReactJS a bit, and was pleasantly surprised when seeing great changes, the JavaScript language has undergone, over the last c.a. 2 years.

This made me realize, that i need to study those changes in more detail, which is how this blog entry came to existence ūüôā

According to Wikipedia, “ECMAScript (or ES) is a scripting-language specification, standardized by the European Computer Manufacturers Association. (‚Ķ) JavaScript is the best-known implementation of ECMAScript since the standard was first published, with other well-known implementations including JScript and ActionScript” (anyone remembering the Flash platform authored by Macromedia?).

In June 2015, sixth edition of ECMAScript (ES6) was introduced, which later changed its name to ECMAScript 2015 (ES2015).

Among the design objectives, that the TC39 (Ecma Technical Committee 39) team defined for the new version of the language, were:

  • Goal 1: Be a better language (for writing: complex applications, libraries (possibly including the DOM) shared by those applications, code generators)
  • Goal 2: Improve interoperation (i.e. adopt de facto standards where possible)
  • Goal 3: Versioning (keep versioning as simple and linear as possible)

Some of the new constructs, that caught my attention:

 

1. let/const vs. var

In ES5, you declare variables via var. Such variables are function-scoped, their scopes are the innermost enclosing functions

In ES6, you can additionally declare variables via let and const. Such variables are block-scoped, their scopes are the innermost enclosing blocks.

let is roughly a block-scoped version of var.

const works like let, but creates variables whose values can’t be changed.

var num = 0;

if (num === 0) {
  let localSpeed = 100;
  var globalSpeed = 200;

  for (let i = 0; i < 0; i++){
    num += (localSpeed + globalSpeed) * 1;
  }

  console.log(typeof i);  // undefined
}

console.log(typeof localSpeed);  // undefined
console.log(typeof num);  // number
console.log(typeof globalSpeed);  // number

General advice by Dr. Axel Rauschmayer (author of Exploring ES6):

  • Prefer const. You can use it for all variables whose values never change.
  • Otherwise, use let ‚Äď for variables whose values do change.
  • Avoid var.

 

2. IIFEs vs. blocks

In ES5, you had to use a pattern called IIFE (Immediately-Invoked Function Expression) if you wanted to restrict the scope of a variable tmp to a block:

(function () {  // open IIFE
  var tmp = ···;
  ···
}());  // close IIFE

console.log(tmp);  // ReferenceError

In ECMAScript 6, you can simply use a block and a let declaration (or a const declaration):

{  // open block
  let tmp = ···;
  ···
}  // close block

console.log(tmp);  // ReferenceError

 

3. concatenating strings vs. template literals

In ES5, you put values into strings by concatenating those values and string fragments:

function printCoord(x, y) {
  console.log('('+x+', '+y+')');
}

In ES6 you can use string interpolation via template literals:

function printCoord(x, y) {
  console.log(`(${x}, ${y})`);
}

Template literals also help with representing multi-line strings.

 

4. function expressions vs. arrow functions

In ES5, such callbacks are relatively verbose:

var arr = [1, 2, 3];
var squares = arr.map(function (x) { return x * x });

In ES6, arrow functions are much more concise:

const arr = [1, 2, 3];
const squares = arr.map(x => x * x);

 

5. for vs. forEach() vs. for-of

Prior to ES5, you iterated over Arrays as follows:

var arr = ['a', 'b', 'c'];
for (var i=0; i<arr.length; i++) {
  var elem = arr[i];
  console.log(elem);
}

In ES5, you have the option of using the Array method forEach():

arr.forEach(function (elem) {
  console.log(elem);
});

A for loop has the advantage that you can break from it, forEach() has the advantage of conciseness.

In ES6, the for-of loop combines both advantages:

const arr = ['a', 'b', 'c'];
for (const elem of arr) {
  console.log(elem);
}

If you want both index and value of each array element, for-of has got you covered, too, via the new Array method entries() and destructuring:

for (const [index, elem] of arr.entries()) {
  console.log(index+'. '+elem);
}

 

6. Handling multiple return values

A. via arrays

In ES5, you need an intermediate variable (matchObj in the example below), even if you are only interested in the groups:

var matchObj = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec('2999-12-31');
var year = matchObj[1];
var month = matchObj[2];
var day = matchObj[3];

In ES6, destructuring makes this code simpler:

const [, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec('2999-12-31');

(The empty slot at the beginning of the Array pattern skips the Array element at index zero.)

B. via objects

In ES5, even if you are only interested in the properties of an object, you still need an intermediate variable (propDesc in the example below):

var obj = { foo: 123 };
var propDesc = Object.getOwnPropertyDescriptor(obj, 'foo');
var writable = propDesc.writable;
var configurable = propDesc.configurable;

console.log(writable, configurable);  // true true

In ES6, you can use destructuring:

const obj = { foo: 123 };
const {writable, configurable} = Object.getOwnPropertyDescriptor(obj, 'foo');
console.log(writable, configurable);  // true true

 

7. Handling parameter default values

In ES5, you specify default values for parameters like this:

function foo(x, y) {
  x = x || 0;
  y = y || 0;
  ···
}

ES6 has nicer syntax:

function foo(x=0, y=0) {
  ···
}

 

8. Handling named parameters

A common way of naming parameters in JavaScript is via object literals (the so-called options object pattern):

selectEntries({ start: 0, end: -1 });

Two advantages of this approach are: Code becomes more self-descriptive and it is easier to omit arbitrary parameters.

In ES5, you can implement selectEntries() as follows:

function selectEntries(options) {
  var start = options.start || 0;
  var end = options.end || -1;
  var step = options.step || 1;
  ···
}

In ES6, you can use destructuring in parameter definitions and the code becomes simpler:

function selectEntries({ start=0, end=-1, step=1 }) {
  ···
}

 

9. arguments vs. rest parameters

In ES5, if you want a function (or method) to accept an arbitrary number of arguments, you must use the special variable arguments:

function logAllArguments() {
  for (var i=0; i<arguments.length; i++) {
    console.log(arguments[i]);
  }
}

In ES6, you can declare a rest parameter (args in the example below) via the …operator:

function logAllArguments(...args) {
  for (const arg of args) {
    console.log(arg);
  }
}

Rest parameters are even nicer if you are only interested in trailing parameters:

function format(pattern, ...args) {
  ···
}

Handling this case in ES5 is clumsy:

function format(pattern) {
  var args = [].slice.call(arguments, 1);
  ···
}

 

10.¬†apply() vs. the spread operator (…)

In ES5, you turn arrays into parameters via apply().

ES6 has the spread operator for this purpose.

A. Math.max() example

ES5 ‚Äď apply():

Math.max.apply(Math, [-1, 5, 11, 3])

ES6 ‚Äď spread operator:

Math.max(...[-1, 5, 11, 3])

B. Array.prototype.push() example

ES5 ‚Äď apply():

var arr1 = ['a', 'b'];
var arr2 = ['c', 'd'];

arr1.push.apply(arr1, arr2); // arr1 is now ['a', 'b', 'c', 'd']

ES6 ‚Äď spread operator:

const arr1 = ['a', 'b'];
const arr2 = ['c', 'd'];

arr1.push(...arr2); // arr1 is now ['a', 'b', 'c', 'd']

 

11.¬†concat() vs. the spread operator (…)

The spread operator can also (non-destructively) turn the contents of its operand into Array elements. That means that it becomes an alternative to the Array method concat().

ES5 ‚Äď concat():

var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];

console.log(arr1.concat(arr2, arr3)); // [ 'a', 'b', 'c', 'd', 'e' ]

ES6 ‚Äď spread operator:

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

console.log([...arr1, ...arr2, ...arr3]); // [ 'a', 'b', 'c', 'd', 'e' ]

 

12. function expressions in object literals vs. method definitions

In JavaScript, methods are properties whose values are functions.

In ES5 object literals, methods are created like other properties. The property values are provided via function expressions.

var obj = {
  foo: function () {
    ···
  },
  bar: function () {
    this.foo();
  }, // trailing comma is legal in ES5
}

ES6 has method definitions, special syntax for creating methods:

const obj = {
  foo() {
    ···
  },
  bar() {
    this.foo();
  },
}

 

13. constructors vs. classes

ES6 classes are mostly just more convenient syntax for constructor functions.

A. Base classes

In ES5, you implement constructor functions directly:

function Person(name) {
  this.name = name;
}
Person.prototype.describe = function () {
  return 'Person called '+this.name;
};

Note the compact syntax for method definitions ‚Äď no keyword function needed.

Also note that there are no commas between the parts of a class

B. Derived classes

Subclassing is complicated in ES5, especially referring to super-constructors and super-properties.

This is the canonical way of creating a sub-constructor Employee of Person:

function Employee(name, title) {
  Person.call(this, name); // super(name)
  this.title = title;
}

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function () {
  return Person.prototype.describe.call(this) // super.describe()
    + ' (' + this.title + ')';
};

ES6 has built-in support for subclassing, via the extends clause:

class Employee extends Person {
  constructor(name, title) {
    super(name);
    this.title = title;
  }
  describe() {
    return super.describe() + ' (' + this.title + ')';
  }
}

 

14. custom error constructors vs. subclasses of Error

In ES5, it is impossible to subclass the built-in constructor for exceptions, Error.

The following code shows a work-around that gives the constructor MyError important features such as a stack trace:

function MyError() {
  var superInstance = Error.apply(null, arguments); // Use Error as a function
  copyOwnPropertiesFrom(this, superInstance);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;

function copyOwnPropertiesFrom(target, source) {
  Object.getOwnPropertyNames(source).forEach(function(propKey) {
    var desc = Object.getOwnPropertyDescriptor(source, propKey);
    Object.defineProperty(target, propKey, desc);
  });
return target;
};

In ES6, all built-in constructors can be subclassed, which is why the following code achieves what the ES5 code can only simulate:

class MyError extends Error {
}

 

15. objects vs. Maps

Using the language construct object as a map from strings to arbitrary values (a data structure) has always been a makeshift solution in JavaScript. The safest way to do so is by creating an object whose prototype is null. Then you still have to ensure that no key is ever the string ‘__proto__’, because that property key triggers special functionality in many JavaScript engines.

The following ES5 code contains the function countWords that uses the object dictas a map:

var dict = Object.create(null);

function countWords(word) {
  var escapedWord = escapeKey(word);
  if (escapedWord in dict) {
    dict[escapedWord]++;
  } else {
    dict[escapedWord] = 1;
  }
}

function escapeKey(key) {
if (key.indexOf('__proto__') === 0) {
    return key+'%';
  } else {
    return key;
  }
}

In ES6, you can use the built-in data structure Map and don’t have to escape keys. As a downside, incrementing values inside Maps is less convenient.

const map = new Map();
function countWords(word) {
  const count = map.get(word) || 0;
  map.set(word, count + 1);
}

Another benefit of Maps is that you can use arbitrary values as keys, not just strings.

 

16. New string methods

A. indexOf vs. startsWith

if (str.indexOf('x') === 0) {} // ES5
if (str.startsWith('x')) {} // ES6

B. indexOf vs. endsWith

function endsWith(str, suffix) { // ES5
  var index = str.indexOf(suffix);
  return index >= 0 && index === str.length-suffix.length;
}
str.endsWith(suffix); // ES6

C. indexOf vs. includes

if (str.indexOf('x') >= 0) {} // ES5
if (str.includes('x')) {} // ES6

D. join vs. repeat (the ES5 way of repeating a string is more of a hack):

new Array(3+1).join('#') // ES5
'#'.repeat(3) // ES6

 

17. New Array methods

A. Array.prototype.indexOf vs. Array.prototype.findIndex

The latter can be used to find NaN, which the former can’t detect:

const arr = ['a', NaN];
arr.indexOf(NaN); // -1
arr.findIndex(x => Number.isNaN(x)); // 1

As an aside, the new Number.isNaN() provides a safe way to detect NaN (because it doesn’t coerce non-numbers to numbers):

isNaN('abc') // true
Number.isNaN('abc') // false

B. Array.prototype.slice() vs. Array.from() (or the spread operator)

In ES5, Array.prototype.slice() was used to convert Array-like objects to Arrays. In ES6, you have Array.from():

var arr1 = Array.prototype.slice.call(arguments); // ES5
const arr2 = Array.from(arguments); // ES6

If a value is iterable (as all Array-like DOM data structure are by now), you can also use the spread operator (…) to convert it to an Array:

const arr1 = [...'abc']; // ['a', 'b', 'c']
const arr2 = [...new Set().add('a').add('b')]; // ['a', 'b']

C. apply() vs. Array.prototype.fill()

In ES5, you can use apply(), as a hack, to create in Array of arbitrary length that is filled with undefined:

// Same as Array(undefined, undefined)
var arr1 = Array.apply(null, new Array(2)); // [undefined, undefined]

In ES6, fill() is a simpler alternative:

const arr2 = new Array(2).fill(undefined); // [undefined, undefined]

fill() is even more convenient if you want to create an Array that is filled with an arbitrary value:

// ES5
var arr3 = Array.apply(null, new Array(2)).map(function (x) { return 'x' }); // ['x', 'x']

// ES6
const arr4 = new Array(2).fill(‚Äėx‚Äô); // ['x', 'x']

fill() replaces all Array elements with the given value. Holes are treated as if they were elements.

 

18. CommonJS modules vs. ES6 modules

Even in ES5, module systems based on either AMD syntax or CommonJS syntax have mostly replaced hand-written solutions such as the revealing module pattern.

ES6 has built-in support for modules. Alas, no JavaScript engine supports them natively, yet. But tools such as browserify, webpack or jspm let you use ES6 syntax to create modules, making the code you write future-proof.

A. Multiple exports in CommonJS

//------ lib.js ------
var sqrt = Math.sqrt;
function square(x) {
  return x * x;
}
function diag(x, y) {
  return sqrt(square(x) + square(y));
}
module.exports = {
  sqrt: sqrt,
  square: square,
  diag: diag,
};

//------ main1.js ------
var square = require('lib').square;
var diag = require('lib').diag;

console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

Alternatively, you can import the whole module as an object and access square and diag via it:

//------ main2.js ------
var lib = require('lib');

console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

B. Multiple exports in ES6

In ES6, multiple exports are called named exports and handled like this:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
  return x * x;
}
export function diag(x, y) {
  return sqrt(square(x) + square(y));
}

//------ main1.js ------
import { square, diag } from 'lib';

console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

The syntax for importing modules as objects looks as follows (line A):

//------ main2.js ------
import * as lib from 'lib'; // (A)

console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

C. Single exports in CommonJS

Node.js extends CommonJS and lets you export single values from modules, via module.exports:

//------ myFunc.js ------
module.exports = function () { ··· };

//------ main1.js ------
var myFunc = require('myFunc');
myFunc();

D. Single exports in ES6

In ES6, the same thing is done via a so-called default export (declared via export default):

//------ myFunc.js ------
export default function () { ··· } // no semicolon!

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

 

 

That would be it,

Cheers!

 

Resources:

Advertisements

Sharing data between controllers in AngularJS (PubSub/Event bus example)

Basically, there are two ways of handling the communication between controllers in AngularJS:

  • using a service which acts as a PubSub/Event bus when injected into controllers:
    • code example (John Lindquist’s fantastic webcast can be found here):
      'use strict';
      angular.module('myAppServices', [])
        .factory('EventBus', function () {
          return {message: "I'm data from EventBus service"}
        });
      
      'use strict';
      angular.module('myAppControllers', ['myAppServices'])
        .controller('FirstCtrl', function ($scope, EventBus) {
          $scope.data = EventBus;
        })
        .controller('SecondCtrl', function ($scope, EventBus) {
          $scope.data = EventBus;
        });
      

 

    • note:
      In case you don’t need a controller anymore on your page, there’s no way (other than manual) to automatically “unsubscribe” such controllers (as of today AngularJS doesn’t support¬†component life-cycle hooks, by the use of which you could wire/un-wire components). This is because of closures used in controllers that are¬†not “de-allocated” (memory) when the function returns. As a result, you’ll be still sending messages to such “unused” controllers.

 

  • depending on the parent/child relation between scopes, you can transmit events using either $broadcast or $emit methods:
    • if the scope of FirstCtrl is parent to the scope of SecondCtrl, you should use $broadcast method in the FirstCtrl:
      'use strict';
      angular.module('myAppControllers', [])
        .controller('FirstCtrl', function ($scope) {
          $scope.$broadcast('UPDATE_CHILD');
        })
        .controller('SecondCtrl', function ($scope) {
          $scope.$on('UPDATE_CHILD', function() {
            // do something useful here;
          });
        });
      

 

    • if there’s no parent/child relation between scopes, you should inject $rootScope into the FirstCtrl and broadcast the event into other controllers (including SecondCtrl) and their corresponding (child in this case) $scope’s:
      'use strict';
      angular.module('myAppControllers', [])
        .controller('FirstCtrl', function ($rootScope) {
          $rootScope.$broadcast('UPDATE_ALL');
        });
      

 

    • finally, when you need to dispatch the event from a child controller (SecondCtrl) to $scope’s upwards , you should use the $emit method:
      'use strict';
      angular.module('myAppControllers', [])
        .controller('FirstCtrl', function ($scope) {
          $scope.$on('UPDATE_PARENT', function() {
            // do something useful here;
          });
       })
        .controller('SecondCtrl', function ($scope) {
          $scope.$emit('UPDATE_PARENT');
       });
      

 

    • note:
      because $broadcast will dispatch events downwards through (all) scope’s hierarchy, it results in a slight performance hit (more details and performance tests results, here).

 

Cheers!

 

 

Resources:

Tricky behavior of AngularJS $resource service.

When using $resource service of AngularJS in one of the projects recently, i faced a tricky problem and thought it may be valuable to share the solution here.

 

Namely, one of the back-end services is returning an Array of String values like this, when making a GET call using a REST client:

[
  "Value_1",
  "Value_2",
  "Value_3",
  (...)
]

 

Having a standard AngularJS service defined like this:

angular.module('myAppBackendService', ['ngResource'])
  .factory('BackendApi', ['$resource', 'BackendHost', 'BackendPort', 'BackendVersion',
    function ($resource, BackendHost, BackendPort, BackendVersion) {
      var connString = BackendHost + ':' + BackendPort + '/' + BackendVersion;
      return {
        values: $resource(connString + '/values/:id',
        {
          id:'@id'
        }, {
          query: {method: 'GET', isArray: true},
          get: {method: 'GET', params:{id:'@id'}, isArray: true},
          save: {method: 'POST', isArray: true}
        })
      };
  }]);

 

and invoked like this

$scope.values = BackendApi.values.get(
  function(value) {
    // do something interesting with returned values here
    $log.debug('Success: Calling the /values back-end service', value);
  },
  function(errResponse) {
    // do something else in case of error here
    $log.debug('Error: Calling the /values back-end service', errResponse);
  });

 

i was getting a successful response from the server, however the data format which i was getting was completely unexpected to me:

[
  {
    "0" : "V",
    "1" : "a",
    "2" : "l",
    "3" : "u",
    "4" : "e",
    "5" : "_",
    "6" : "1"
  },
  {
    "0" : "V",
    "1" : "a",
    "2" : "l",
    "3" : "u",
    "4" : "e",
    "5" : "_",
    "6" : "2"
  }
]

you can imagine my surprise when trying to figure out what the heck was wrong with it?

 

After spending some time trying to google out a solution, i finally found the reason for such behavior. Listen to this:

“…ngResource¬†expects an object or an array of¬†objects¬†in your response”

“…When¬†isArray¬†is set to¬†true¬†in the list of actions, the¬†ngResource¬†module iterates over each item received in the response and it creates a new instance of a Resource. To do this Angular performs a deep copy between the item received and the¬†Resource¬†class, which gives us an object with special methods ($save,¬†$deleteand so on)”

“…Internally angular uses¬†angular.copy¬†to perform the deep copy and this function only operates with¬†objects¬†andarrays, when we pass a string, it will treat it like an object.

Strings in JS can behave as arrays by providing sequential access to each character. angular.copy will produce the following when passed a string

angular.copy('hi',{}) => {0:'h', 1:'i'}

Each character becomes a value in an object, with its index set as the key.¬†ngResource¬†will provide a resource with properties¬†0¬†and¬†1.”

 

 

So, what are the possible solutions then?

  1. Use the “transformResponse” action of $resource service (you can read more about this in the documentation of the service itself,¬†here)
  2. Use the lower level $http service:
    $http.get('/res').success(function(data){
      $scope.test = data;
    });
    
  3. Return an array of objects in your json response:
    [
      {'data': "hello"},
      {'data': "world"}
    ]
    

 

Happy coding!

 

 

 

 

Resources:

AngularJS custom HTTP headers in resource service

Recently i had to make an HTTP call from the browser (client-side) using JavaScript / AngularJS to a REST API (server-side) and retrieve data. Since the authentication mechanism of the API required a security token to be passed over with the request, i studied AngularJS specs on how to do it best. Basically, there are two ways to do it, either as a:

  1. query parameter, or
  2. custom HTTP header

 

Because i didn’t wanted the security token to appear anywhere in the logs or debugging console (like on the picture below, in case of making use of option 1 just mentioned, ie. query parameter), i decided on passing the token as a custom (there’s no standard header for passing tokens)¬†HTTP header.

AngularJS query API token

 

Since i use Yeoman (app workflow/scaffolding tool) i noticed that through a standard angular-template used for generating an application scaffolding, you’re getting dependency on angular framework in version 1.0.7 (last stable version as of writing this post). Although this is what you would generally expect (stable version, not a snapshot), the problem is that angular documentation for $resource service (which is what i prefer to use over $http service), does not mention¬†the possibility of sending HTTP headers¬†(regarding $http – i think of it as a solution for rather “general purpose AJAX calls”).

 

One way to set HTTP headers is by accessing $httpProvider.defaults.headers configuration object, like this:

$httpProvider.defaults.headers.get['API-Token'] = 'vy4eUCqpQmGoeWsnHKwCQw'

(more documentation about that you’ll find here), but this way you’re modifying¬†$httpProvider globally which may not be what you exactly want.

 

Google search came with help and i found issue 736, which acknowledges that “$resource should support custom http headers”, but it is with the (unstable) release 1.1.3 where this feature is supported for sure (maybe earlier “unstable” versions do support it too, haven’t checked that actually, but definitely none of the stable versions do, as of today).

 

So, what is it that you have to do in order to introduce an unstable version of AngularJS into your project managed by Bower?

bower install angular-unstable
bower install angular-resource-unstable

(dependency on angular-resource.js is required in order for it to work).

 

Now, the only other thing left to do is to update your index.html file accordingly (to make use of proper version of libraries) :

<script src="bower_components/angular-unstable/angular.js"></script>
<script src="bower_components/angular-resource-unstable/angular-resource.js"></script>

 

…and you can start adding custom HTTP headers in your code:

angular.module('usersService', ['ngResource'])
    .factory('User', function($resource, api-token) {
        var User = $resource('http://api.test.com\\:8080/1.0/users', { }, {
            query: {
                method: 'GET',
                isArray: true,
                headers: { 'API-Token': api-token }
            }
        });
        return User
    });

 

Hope this short post will save some of your time ūüôā Cheers!

 

 

Resources:

AngularJS, Karma and debugging unit tests in WebStorm or IntelliJ IDEA

Recently i had to debug few Javascript unit tests in WebStorm IDE and was wondering if it’ll be as easy of an experience as it is in case of Java and IntelliJ IDEA (where i originally come from).

WebStorm 6 doesn’t offer native Karma test runner support (ver 7 which is currently in EAP, does – details here), but using a NodeJS plug-in¬†you can execute any kind of NodeJS application (Karma included).

 

OK, what we’ll need in this exercise is following:

  • One of two JetBrains IDE’s, either:
    • WebStorm (great for JavaScript code) or
    • IntelliJ IDEA (Java’s no. 1 IDE)
  • NodeJS plug-in installed in the IDE:
    • WebStorm comes having it already pre-installed
    • in case of IDEA (Ultimate version, because Community Edition doesn’t have the required JavaScript plug-in for it to work, see here) the plug-in can be downloaded from here.
  • NodeJS environment which can be downloaded from here.
  • Karma (old name Testacular) test runner installed (“npm install -g karma”) that allows running unit (or E2E) tests in one of these browsers:
    • Chrome
    • ChromeCanary
    • Firefox
    • Opera
    • Safari (only Mac)
    • PhantomJS
    • IE (only Windows)
  • Chrome/Firefox “JetBrains IDE Support” extension (required for debugging) that can be downloaded from here.

 

Installing the NodeJS plug-in in IntelliJ IDEA:

  • Open ‚ÄúSettings‚ÄĚ dialog (File -> Settings‚Ķ in the menu bar)
  • Select ‚ÄúPlugins‚ÄĚ (under ‚ÄúIDE Settings‚ÄĚ)
  • Click ‚ÄúBrowse repositories‚Ķ‚ÄĚ
  • Click ‚ÄúDownload and Install‚ÄĚ on¬†the ‚ÄúNodeJS‚ÄĚ plug-in
  • Press ‚ÄúRestart‚ÄĚ when asked, to restart the IDE

 

Configuring IDE to execute Karma test in NodeJS using the plug-in:

  • Open the Run/Debug Configuration dialog by selecting ‚ÄúEdit Configurations‚ÄĚ in the Run area of the main toolbar of WebStorm.
  • Add the following two configurations (picture below):
    • ‚ÄúKarma Run‚ÄĚ: to perform a ‚Äúsingle run‚ÄĚ of your unit tests.
    • ‚ÄúKarma Server‚ÄĚ: to start Karma in ‚ÄúContinuous Integration‚ÄĚ mode (automatic re-runs of your tests whenever files change).
  • Configure the ‚ÄúKarma Run‚ÄĚ configuration:
    • Press the ‚Äú+‚ÄĚ button in the top-left of the ‚ÄúRun/Debug Configurations‚ÄĚ dialog.
    • Select ‚ÄúNode.js‚ÄĚ in the list
    • Fill in the following fields:
      • Name: enter ‚ÄúKarma Run‚ÄĚ
      • Path to Node: absolute path to NodeJS executable (i.e. ‚Äúc:\NodeJS\node.exe‚ÄĚ)
      • Working Directory: absolute path of your AngularJS application (i.e. ‚ÄúC:\MyProjects\AngularApp‚ÄĚ)
      • Path to Node App JS File: Should point to the (globally, ie. -g) installed ‚ÄúKarma‚ÄĚ NodeJs executable (i.e. ‚ÄúC:\Users\…\AppData\Roaming\npm\node_modules\karma\bin\karma‚ÄĚ)
      • Application Parameters: run karma.conf.js¬†–single-run –no-auto-watch –reporters dots
    • Press ‚ÄúApply‚ÄĚ
  • Configure the ‚ÄúKarma Server‚ÄĚ configuration:
    • Essentially take the same steps as while configuring “Karma Run”, changing only the following:
      • Name: enter ‚ÄúKarma Run‚ÄĚ
      • Application Parameters:¬†start¬†karma.conf.js¬†–no-single-run –auto-watch –reporters dots
  • Configure the¬†‚ÄúKarma Debug‚ÄĚ configuration¬†to allow debugging of Karma unit tests
    • Press the ‚Äú+‚ÄĚ button in the top-left of the ‚ÄúRun/Debug Configurations‚ÄĚ dialog.
    • Select “JavaScript Debug¬†->¬†Remote” in the list
    • Fill in the following fields:
      • Name: enter ‚ÄúKarma Debug‚ÄĚ
      • URL to open:¬†http://localhost:8100/debug.html (port number depends on your configuration in karma.conf.js file (passed as an “Application Parameter” in the previous two configurations)
      • Browser: chose either¬†Chrome¬†or¬†Firefox
      • Set the “Remote URL”¬†field to point to ‚Äúhttp://localhost:8100/base‚ÄĚ

        Karma Debug configuration in IntelliJ WebStorm

 

Finally, run your “Karma Server” configuration and while it’s working in the background (–auto-watch mode), set debugging breakpoints in your code and fire “Karma Debug” configuration.

That’s it. Hope this small guide turns out to be helpful.

 

Resources:

AngularJS basics

I’ve been reading a great introductory book on AngularJS recently (authored by Brad Green and Shyam Seshadri) and thought i’ll share with you some of my notes (prior to going further with reading however, i strongly advise to watch few videos on the subject from the wonderful¬†egghead.io¬†website):

  • The role of the server:
    • Traditional Web Apps – create HTML pages by assembling components (header, content, footer, etc.), joining it with the data and then shipping it all over the wire¬†to the browser to display.
    • AngularJS Apps – serve static resources (HTML templates, media, etc.) and data to the browser which takes care of assembling.
  • “By structuring your application with Angular, your application‚Äôs templates are kept separate¬†from the data that populates them. The result of this is that these templates are¬†cacheable. Only new data need to come down to the browser after the first load. Just¬†as with JavaScript, images, CSS, and other resources, caching these templates can give¬†your application even better performance.”
  • Model-View-Controller (MVC)
    • application architecture that separates the code between:
      • model – managing data (which is stored in object properties)
      • controller – managing the application logic (javascript classes)
      • view – presenting the data to the user (DOM)
    • “The view gets data from the model to display to the user. When a user interacts with the¬†application by clicking or typing, the controller responds by changing data in the model.¬†Finally, the model notifies the view that a change has occurred so that it can update what¬†it displays.”
  • Data binding
    • “…just declare which parts of the UI map to which JavaScript properties and have¬†them sync automatically.”
    • use double-curly syntax {{someText}} or ng-bind=”someText” directive¬†to insert new content into an existing HTML¬†template (with the double-curly syntax, on the very first page load of your¬†application‚Äôs index.html, there‚Äôs a chance that your user will see the un-rendered template¬†before Angular has a chance to replace the curlies with your data).
  • Dependency Injection (definition taken from Craig Walls “Spring in Action” 3rd ed.)
    • Any nontrivial application¬†is made up of two or more classes that collaborate with each other to¬†perform some business logic. Traditionally, each object is responsible for obtaining its¬†own references to the objects it collaborates with (its dependencies). This can lead to code which is:
      • highly coupled
      • hard-to-test
      • difficult to reuse
      • difficult to understand
      • code that ¬†typically exhibits ‚Äúwhack-a-mole‚Ä̬†bug behavior (fixing one bug results in the creation of one or more new bugs)
    • With DI, on the other hand, objects are given their dependencies at creation time¬†by some third party (usually specialized DI framework) that coordinates each object in the system. Objects aren’t¬†expected to create or obtain their dependencies‚ÄĒdependencies are injected into the¬†objects that need them.
  • Directives:
    • in AngularJS you can write your templates as HTML,¬†because at the core of the framework there is a powerful DOM transformation¬†engine included¬†that lets you extend HTML‚Äôs syntax (ng-app, ng-controller, ng-model and similar directives).
  • To invoke AngularJS you must:
    • Load the angular.js library (eg. from¬†Google‚Äôs CDN (content delivery network), ie.:¬†https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js”)
    • Tell Angular which part of the DOM it should manage with the ng-app directive (eg.¬†<html ng-app>)
  • Basic AngularJS app startup flow:
    • A user requests the first page of your application.
    • The user‚Äôs browser makes an HTTP connection to your server and loads the index.html page containing your template.
    • Angular loads into the page, waits for the page to be fully loaded, and then looks¬†for ng-app to define its template boundaries.
    • Angular traverses the template and looks for directives and bindings. This results¬†in registration of listeners and DOM manipulation, as well as fetching initial data¬†from the server. The end result of this work is that the app is bootstrapped and the¬†template is converted into view as a DOM.
    • You connect to your server to load additional data you need to show the user as¬†needed.
  • Rationale behind writing¬†‚Äúunobtrusive JavaScript‚ÄĚ code (eg. not¬†using click, mousedown, and¬†other such inline event handlers in your HTML) and how AngularJS re-examine the problem:
    • Not everyone‚Äôs browser supports JavaScript. Let everyone see all of your content¬†and use your app without needing to execute code in the browser.
      • this is no longer true as if you‚Äôre running a browser without JavaScript, you‚Äôre relegated¬†to sites created in the ’90s
    • Some folks use browsers that work differently. Visually impaired folks who use¬†screen-readers and some mobile phone users can‚Äôt use sites with JavaScript.
      • modern screen-readers have caught¬†up. With proper use of ARIA semantic tags, you can make very rich UIs easily accessible.¬†Mobile phones now run JavaScript on par with desktop machines.
    • Javascript works differently across different platforms. IE is usually the culprit here.¬†You need to put in different event-handling code depending on the browser.
      • Angular has an equivalent in¬†the form of ng-eventhandler=”expression” where eventhandler would be replaced¬†by click, mousedown, change, and so on.¬†AngularJS directives differ from their event handler predecessors in that they b

        ehave the same in every browser. Angular takes care of the differences for you.

    • These event handlers reference functions in the global namespace. It will cause you¬†headaches when you try to integrate other libraries with functions of the same¬†names.
      • Similarly to the previous point, AngularJS¬†equivalent¬†eventhandlers¬†do not operate on the global namespace. The expressions you specify can only¬†access functions and data that is in the scope of the element‚Äôs controller.
    • These event handlers combine structure and behavior. This makes your code more¬†difficult to maintain, extend, and understand.
      • There‚Äôs a simple acid test we can use to figure out if our system suffers from this coupling:¬†can we create a unit test for our app logic that doesn‚Äôt require the DOM to be present?¬†In Angular, yes we can write controllers containing our business logic without having¬†references to the DOM.
  • While angular is a client-side-only technology and it’s possible to create angular web apps that don’t require a back-end server at all, it is recommended to host the project files using a local web-server during development to avoid issues with security restrictions (sandbox) in browsers. The sandbox implementation varies between browsers, but quite often prevents things like cookies, xhr, etc to function properly when an html page is opened via¬†file://¬†scheme instead of¬†http://.

JavaScript Toolset

Below you’ll find a short list specifying toolset that may be helpful when developing JavaScript code:

  1. Node.js –¬†a platform built on¬†Chrome’s JavaScript runtime¬†for easily building fast, scalable network applications. It uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.
  2. NPM¬†–¬†node package manager (part of Node.js)
  3. Yeoman¬†–¬†a robust and opinionated client-side stack, comprising tools and frameworks that can help developers quickly build web applications
  4. Bower – package manager for javascript libraries
  5. Karma¬†–¬†Spectacular Test Runner for JavaScript
  6. WebStorm¬†–¬†The smartest JavaScript IDE
  7. Jasmine Рa behavior-driven development (BDD) framework that allows writing specifications that denote how your code should behave.
  8. Batarang –¬†Extends Chrome’s Developer Tools, adding tools for debugging and profiling AngularJS application
  9. RequireJS –¬†a JavaScript file and module loader

 

Also, there are tools you’ll be using less frequently (especially, if you decide to go with Yeoman as Yo integrates many of them), but still it’s good to know what they do:

  1. angular-seed –¬†seed project (an application skeleton) for angular apps.¬†You can use it to quickly bootstrap your angular webapp projects and dev environment for these projects.¬†The seed contains AngularJS libraries, test libraries and a bunch of scripts all pre-configured for instant web development gratification. Just clone the repo (or download the zip/tarball), start up our/provided (or yours) webserver and you are ready to develop and test your application.
  2. underscore.js –¬†a utility-belt library for JavaScript that provides a lot of the functional programming support¬†for the usual functional suspects (each, map, reduce, filter…) without extending any core JavaScript objects.
  3. angular-mocks.js – contains an implementation of mocks that makes testing angular apps easier.
  4. angular-scenario.js – a nifty JavaScript lib that allows you to write and execute end-to-end tests for angular applications
  5. angular-loader.js – module loader for Angular modules. If you are loading multiple script files containing Angular modules, you can load them asynchronosuly and in any order as long as you load this file first.
  6. angular-resource.js – provides $resource service that¬†makes it possible to execute HTTP calls (eg. against REST API’s)
  7. angular-cookies.js – provides two services: $cookies and $cookieStore.
  8. angular-sanitize.js – provides ngBindHtml directive, linky filter and $sanitize service.