Web Development13 Aug 2014 06:01 am

The AngularJS $http service is great for most any communication you need to do with the web services that are likely backing your single-page-application. However one place where it doesn’t quite do what you usually want is in the deserialization of dates.

Using $http to post a blog entry for example is pretty easy:

myPost = 
  id: 123
  title: 'Using HTTP Interceptors to Deserialize Dates'
  status: 'draft'
  creationDate: new Date()
  body: 'TBD'
 
$http.post('/api/blog', myPost)

This results in the following JSON being posted to the server:

{
  "id": 123
  "title": "Using HTTP Interceptors to Deserialize Dates",
  "status": "draft",
  "creationDate": "2014-08-13T10:13:39.399Z",
  "body": "TBD"
}

This is great. Notice that the service has automatically serialized the creation date to an ISO-8601 compliant string. I couldn’t ask for more… or could I?

What if I want to now get that post back:

$http.get("/api/blog/123").success (blog) ->
    console.log blog.creationDate    
    console.log typeof blog.creationDate

Assuming that the endpoint returns the exact same JSON that was just posted, this code will output:

2014-08-13T10:13:39.399Z
string

This is not the end of the world but it may not be what one is expecting. The expectation is usually that if I put a Date instance into a serialization function, then I get a Date instance out of the matching deserialization function.

Fortunately, this situation is easily remedied with a Angular http interceptor. Angular’s $httpProvider service allows one to configure interceptors that can pre-process all out-going requests before they are sent and post-process all received responses before handing them back to the calling application. A response post-processor to find all ISO-8601 date strings and convert them to actual Date objects is easy to implement.

angular.module('myModule', []).config([
  '$httpProvider'
  ($httpProvider) ->
    $httpProvider.interceptors.push [
      ->
        #Matches YYYY-MM-ddThh:mm:ss.sssZ where .sss is optional
        iso8601RegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/
 
        response: (response) ->
 
          convertDates = (obj) ->
 
            for key, value of obj
 
              #If it is a string of the expected form convert to date  
              type = typeof value
              if type is 'string' and iso8601RegEx.test value
                  obj[key] = new Date(value)
 
              #Recursively evaluate nested objects
              else if type is 'object'
                convertDates value
 
          convertDates response.data
 
          response
    ]
])

And there you have it. Happy coding!

Web Development14 Jan 2014 09:03 am

Figuring out load order issues in Require.JS can be a big pain some times. However, if you are using the non-minified version, its easy to add some instrumentation that makes things clear. The Require.JS code is well documented so feel free to look around. I find the following methods most helpful to instrument.

@@ -1517,10 +1517,11 @@ var requirejs, require, define;
              * A load event could be a script load or just a load pass from a synchronous
              * load call.
              * @param {String} moduleName the name of the module to potentially complete.
              */
             completeLoad: function (moduleName) {
+                console.log('Completed load of ' + moduleName);
                 var found, args, mod,
                     shim = getOwn(config.shim, moduleName) || {},
                     shExports = shim.exports;
 
                 takeGlobalQueue();
@@ -1635,10 +1635,11 @@ var requirejs, require, define;
             },
 
             //Delegates to req.load. Broken out as a separate function to
             //allow overriding in the optimizer.
             load: function (id, url) {
+                console.log('Loading ' + id + ' from ' + url);
                 req.load(context, id, url);
             },
 
             /**
              * Executes a module callback function. Broken out as a separate function
@@ -1646,10 +1647,11 @@ var requirejs, require, define;
              * layer in the right sequence.
              *
              * @private
              */
             execCb: function (name, callback, args, exports) {
+                console.log('Initializing ' + name);
                 return callback.apply(exports, args);
             },
 
             /**
              * callback for script loads, used to check status of loading.

F.Y.I. This diff was applied to Require.JS 2.1.10

Software Development11 Dec 2013 10:05 pm

The Problem

Recently, I have been doing some in-browser automated testing with Testem and Mocha. For continuous integration purposes we are using the PhantomJS headless browser.

All was fine until one day when—boom—a bunch of new tests, which I had written and debugged in Chrome and FireFox, were failing in CI under Phantom. It turns out that Phantom 1.9 has some date parsing issues and cannot parse dates of the form “2011 Feb 09 12:39:09.”

We had previously used a ISO-8601 polyfill to fix a similar problem with legacy Firefox browsers. This problem was a little different. Our date format, though understood by most browsers, isn’t ISO-8601 compliant. More importantly, the polyfill only fixed the “static” Date.parse method. In the current case, the date was being parsed by the Date constructor.

The ISO-8601 polyfill explicitly avoided dealing with the constructor and for good reason. Though I did not know it at the time, JavaScript never intended for anyone to subclass its internal Date type. (More on this later.) Changing our code over to use Date.parse and modifying the polyfill would mean touching a lot of code, and making it more complex, just for CI—something I didn’t want to do. So I set out to write my own polyfill that would handle the constructor as well as Date.parse.

Initial Attempts: Subclassing Date

My initial simple-minded approach was to just subclass Date and override its constructor, like so:

(function () {
 
    function fixStringDate (sDate) {
        //Implementation omitted for brevity
        return sDate;
    }
 
    Date = (function (JSDate) {
 
        function ctor() {
            this.constructor = newDate;
        }
        ctor.prototype = JSDate.prototype;
        newDate.prototype = new ctor();
 
        function newDate() {
            if (arguments.length === 1 && typeof arguments[0] === "string") {
                JSDate.prototype.constructor.call(null, fixStringDate(arguments[0]));
            } else {
                JSDate.prototype.constructor.apply(null, arguments);
            }
        }
 
        newDate.parse = function (sDate) {
            return JSDate.parse(fixStringDate(sDate));
        }
 
        return newDate;
 
    })(Date)
 
})();

As you can see, this is pretty much boilerplate code for creating a subclass in JavaScript. And it seemed to work. After running the code, calls like new Date(’2011 Feb 09 12:39:09′) no longer threw errors in PhantomJS. That’s the good part.

The bad part is that calling any instance method of the object so created results in a TypeError with a message to the effect of “not a date object”. This stackoverflow question outlines the issue very well. In short, Date isn’t really so much a class as a collection of static methods that only allow themselves to be called with an object whose immediate type is Date. Mere sub-types of Date don’t pass muster.

So the obvious thing to do was to create a real date object internal to the new class and delegate all method calls down to it. Thus:

function newDate() {
    if (arguments.length === 1 && typeof arguments[0] === "string") {
        JSDate.prototype.constructor.call(null, fixStringDate(arguments[0]));
        this.__realDateObject = new JSDate(fixStringDate(arguments[0]))
    } else {
        JSDate.prototype.constructor.apply(null, arguments);
        this.__realDateObject = JSDate.apply(null, arguments);
    }
}
 
var functions = ["getDate", "getDay", ... "valueOf"]
for (var i = 0; i < functions.length; i++) {
    (function (funcName) {
        newDate.prototype[funcName] = function () {
            return JSDate.prototype[funcName].apply(this.__realDateObject, arguments);
        };
    })(functions[i]);
}

This solved the problem for our specific cases and I could have stopped here. We fortunately never invoked the constructor with more than one argument.

Since we might do otherwise in the future, I wrote some tests to cover all the cases. In doing so, I found out that calling apply on JSDate (a reference to the original Date class) does not work. It runs, but the object returned is “not a Date object.”

I messed around with a lot of ways to invoke apply on the JSDate constructor including several worthy of mention. None worked in this case. Ultimately I had to resort to brute force, relying on the fact that the Date constructor accepts a reasonably finite number of arguments:

function newDate() {
    if (arguments.length === 1 && typeof arguments[0] === "string") {
        JSDate.prototype.constructor.call(null, fixStringDate(arguments[0]));
        this.__realDateObject = new JSDate(fixStringDate(arguments[0]))
    } else {
        JSDate.prototype.constructor.apply(null, arguments);
        if (arguments.length == 1)
            this.__realDateObject = new JSDate(arguments[0]);
        else if (arguments.length == 2)
            this.__realDateObject = new JSDate(arguments[0], arguments[1]);
        //etc...
    }
}

At this point it became obvious that newDate isn’t really acting as a subclass at all. It is acting more like a decorator around the Date type. So all the subclassing code can be removed, which gets us to:

(function () {
 
    function fixStringDate (sDate) {
        //Implementation omitted for brevity
        return sDate;
    }
 
    Date = (function (JSDate) {
 
        function newDate() {
            if (arguments.length === 1 && typeof arguments[0] === "string") {
                this.__realDateObject = new JSDate(fixStringDate(arguments[0]))
            } else {
                if (arguments.length == 1)
                    this.__realDateObject = new JSDate(arguments[0]);
                else if (arguments.length == 2)
                    this.__realDateObject = new JSDate(arguments[0], arguments[1]);
                //etc...
             }
        }
 
        var functions = ["getDate", "getDay", ... "valueOf"]
        for (var i = 0; i < functions.length; i++) {
            (function (funcName) {
                newDate.prototype[funcName] = function () {
                    return JSDate.prototype[funcName].apply(this.__realDateObject, arguments);
                };
            })(functions[i]);
        }
 
        newDate.parse = function (sDate) {
            return JSDate.parse(fixStringDate(sDate));
        }
 
        return newDate;
 
    })(Date)
 
})();

The Final Solution

Having done this, I realized I was making everything much harder than it needed to be. If I am not actually subclassing Date and just decorating it, all I really need to do is decorate the constructor and return a real Date object from it. Doing so lets me drop all that messy delegation code for the instance methods. Finally my code becomes simple and clean:

(function () {
 
    function fixStringDate (sDate) {
        //Implementation omitted for brevity
        return sDate;
    }
 
    Date = (function (JSDate) {
 
        function newDate() {
            var theDate;
            if (arguments.length === 1 && typeof arguments[0] === "string") {
                theDate = new JSDate(fixStringDate(arguments[0]))
            } else {
                if (arguments.length == 1)
                    theDate = new JSDate(arguments[0]);
                else if (arguments.length == 2)
                    theDate = new JSDate(arguments[0], arguments[1]);
                //etc...
             }
             return theDate;
        }
 
        newDate.parse = function (sDate) {
            return JSDate.parse(fixStringDate(sDate));
        }
 
        return newDate;
 
    })(Date)
 
})();

Intuition tells me this code has some drawbacks that could merit a return to the subclassing solution for certain edge cases. So I am glad to have gone through the whole learning experience. Yet for now, the simpler solution is enough. YAGNI

Full code with tests is available on GitHub.

Next Page »