Monday, February 25, 2013

JavaScript - Dynamic Prototyping

There are thousands of JavaScript prototype tutorials online


Okay, so most people know about and/or understand JavaScript's prototypical inheritance system. Every object has a prototype which is an object, and when you look for a property on that object, if it doesn't have it, it checks the prototype for the property, and if it doesn't have it, it checks prototype's prototype for the property, etc. etc. (If anyone really wants me to do an entry on this, let me know, but rest assured it's pretty well covered elsewhere)


First let me go over the plain, boring ways prototype is commonly used

(It gets better further down)

In practice, 99% of the time, JavaScript's prototype ends up getting used like this:

//create some class.
function Foo() {
}

//add some properties to it.
Foo.prototype.test = function () {
   alert('wee');
};
Foo.prototype.bar = 123;

//use it.
var foo = new Foo();
foo.test(); //alert wee
console.log(foo.bar); //123


Boring. Boring. Boring.


Then occasionally you'll see some blog entry come along about "OOP in JS" or whatever and you'll see prototype getting used like so:

//create a class.
function Foo(){
}
Foo.prototype.test = 'wee';

//create another class.
function Bar() {
}
//that inherits from the first class.
Bar.prototype = new Foo();

//try it out.
var bar = new Bar();
console.log(bar.test); //wee


Okay, well that's a little more interesting, right? We've got some semblance of two class definitions where one inherits from the other. Pretty cool, I guess. Still not terribly exciting, though.


Dynamic Prototyping! (Finally something interesting)


I'm sure there's a better word for it, but I'm calling it "Dynamic Prototyping" (it's my blog!). JavaScript is dynamic and fun. Certainly we can do something cooler with this right? I mean, this seems like something we can really hack to our advantage. And then I saw what AngularJS was doing with prototypical inheritance. They were using it in a dynamic way, allowing "scopes" to inherit from one another, and changes to propagate from parent to child (but not child to parent). Check this out:

//create a class
function Foo(){ 
}

//Give it a method to create child clones of itself
Foo.prototype.spawnClone = function() {
    //Dynamically assign the current instance as a prototype.
    Foo.prototype = this;
    //return a new one
    return new Foo();
};

//Give it a try
var foo = new Foo();
foo.bar = 'test';
var fooSpawn = foo.spawnClone();
alert(fooSpawn.bar); //test

//so far, so good, but watch this:
foo.bar = 'weee';

//we actually updated the child by updating the parent!
alert(fooSpawn.bar); //weee


Now that's cool! Now I can take an object, and create a "child object" that not only inherits its properties, but is actually bound to that object programmatically. Granted, it's a one way binding, but it's still a lot of fun.


Watch out! Prototypical Madness!


So, we learned that we can dynamically prototype a constructor function. That's pretty cool. But watch out! The class will use whatever prototype was assigned to it last!

See where we can run into problems here (assuming the above code):

var foo = new Foo();
var fooSpawn = foo.spawnClone();
foo.bar = 'test';

var foo2 = new Foo();
//OOPS: We don't want this! We've messed with the prototype and it stuck!
alert(foo2.bar); //test


The fix to get around that is simple, you just need to do one of two things: Copy off the original prototype and reassign it after the child is created and/or use an extend method (such as JQuery's extend) to augment your child class's prototype prior to created a new instance:

function Foo() {
}

Foo.prototype.betterSpawnClone = function (){
    //create a copy of the current prototype.
    var protoCopy = Foo.prototype;
    //dynamically assign the prototype.
    Foo.prototype = this;
    //create the clone.
    var clone = new Foo();
    //reset the prototype back to normal.
    Foo.prototype = protoCopy;
    //return our clone.
    return clone;
}

Anyhow, here's a fiddle to play with. It's a fun little trick with JavaScript and I hope it's useful to someone:

Wednesday, February 13, 2013

AngularJS: Creating A Service With $http

So I did a talk on AngularJS last night at the Pittsburgh .NET Users' Group. It was a great talk and you guys asked a lot of great questions. One of my friends that attended suggest people use my blog as a resource for Angular, and while I do have quite a few posts about Angular, I don't feel like it's quite as flushed out in that department as I'd like it to be before I wanted my friends plugging it like that. So I've decided to try to fill that gap, at least as far as Angular goes, over the next few weeks, if I can. (Don't worry, PGHNUG attendees, I'll still try to get a well commented Angular/Web API solution up on GitHub soon).


HTTP Service Calls In Angular


One of the most common questions I see on StackOverflow regarding Angular, are questions involving the creation of AJAX-based angular services using $http. Commonly the pattern used is very reminiscent of JQuery, where there's a method with a callback when the data is received.

Common Callback Example


app.factory('myService', function($http) {
   return {
     getFooOldSchool: function(callback) {
       $http.get('foo.json').success(callback);
     }
   }
});

app.controller('MainCtrl', function($scope, myService) {
  myService.getFooOldSchool(function(data) {
     $scope.foo = data;
  });
});


That's fine. It's an easy to understand pattern that is predictable for most other developers using your service and most importantly, it works.


Angular Loves Promises

In Angular, there is a service called $q. It is a deferred/promise implementation built off of Q by Kristopher Kowal. I know I've talked about deferment and promises in JavaScript in the past, but as a very quick refresher, the idea behind this pattern is basically to have a mechanism to signal when one (or sometimes many) asynchronous actions are complete. It's the hub of JQuery's AJAX implementation, Angular $http implementation and Angular's $resource implementation. I like this mechanism so much I've even implemented it in my .NET Event Loop Framework.

EDIT: As of 1.2.0, promises are no longer resolved by templates.

So in code, that means if you return a promise from your service, and put it directly in a scope property, it will asynchronously update that scope property and process the changes.

Since $http methods like get() and post() return promises, we can use that promise's then() method (which also returns a promise) to pull the data out of the result. The return value from the then() method's callback is used to resolve that promise.

Simplified Promise Pattern Example


app.factory('myService', function($http) {
   return {
     getFoo: function() {
       //since $http.get returns a promise,
       //and promise.then() also returns a promise
       //that resolves to whatever value is returned in it's 
       //callback argument, we can return that.
       return $http.get('foo.json').then(function(result) {
           return result.data;
       });
     }
   }
});

app.controller('MainCtrl', function($scope, myService) {
   //DEPRECATED: The commented line below WILL NO LONGER WORK in 1.2.0
   //since promises are no longer resolved by templates.
   //$scope.foo = myService.getFoo();

   //make the call to getFoo and handle the promise returned;
   myService.getFoo().then(function(data) {
       //this will execute when the 
       //AJAX call completes.
       $scope.foo2 = data;
       console.log(data);
   });
};



And because some of you like to play around, here's a bit of code on plunker showing the promise pattern for $http calls in Angular:


Edit: Complex $http calls from within a Service


Because I've been asked by friends what to do in situations where you might have nested or simultaneous async calls in a controller, I think this blog entry is a really good place to show some examples of that, since it falls under the same domain, so to speak.

There are of course scenarios where you might have a service method that requires more than one $http call (or other async call) to be made before you want the service to return. This is where you'd want to use the $q service mentioned above.

Example of dealing with multiple async calls to return simultaneously


app.factory('myService', function ($http, $q){
  return {
    getItems: function (){
      //$q.all will wait for an array of promises to resolve,
      // then will resolve it's own promise (which it returns)
      // with an array of results in the same order.
      return $q.all([
        $http.get('items_part_1.json'),
          $http.get('items_part_2.json')
      ])
        
      //process all of the results from the two promises 
      // above, and join them together into a single result.
      // since then() returns a promise that resolves ot the
      // return value of it's callback, this is all we need 
      // to return from our service method.
      .then(function(results) {
        var data = [];
        angular.forEach(results, function(result) {
          data = data.concat(result.data);
        });
        return data;
      });
    }
  };
});


Example of dealing with nested async calls in a single service call

Technically, we can deal with nested async calls without using $q. ("nested" to say that each call to $http triggers a subsequent call to $http in order to build out some data) This simplifies the code a little, but in my opinion makes it harder to follow.  For example:

 getNestedData: function (){ 
      // get the parents.
      return $http.get('parents.json')
        .then(function(result) {          
          //return a promise to that data.
          return result.data;
        })
        //handle the promise to the parent data
        .then(function(parents) {         
          //get the children.
          return $http.get('children.json')
            //handle the promise to the children.
            .then(function(result) {            
              //add children to the appropriate parent(s).
              var children = result.data;
              angular.forEach(parents, function(parent) {
                parent.children = [];            
                angular.forEach(children, function(child) {
                  if(parent.childIds.indexOf(child.id) >= 0) {
                    parent.children.push(child);
                  }
                });
              });              
              //return the parents
              return parents;
            });
        });
    }


Example of nested calls using $q directly

This is a point where it really doesn't matter which route you go when it comes to what's going to work. However, it is my opinion that using $q directly in complicated async calls or nested async calls, enhances readability. This is simply because it becomes easier to see which promise was returned, when it was created, and where it was resolved:


getNestedDataBetter: function (){
  //create your deferred promise.
  var deferred = $q.defer();
  
  //do your thing.
  $http.get('parents.json')
    .then(function(result){
      var parents = result.data;
      $http.get('children.json')
        .then(function(result) {
          var children = result.data;
            angular.forEach(parents, function(parent) {
              parent.children = [];            
              angular.forEach(children, function(child) {
                if(parent.childIds.indexOf(child.id) >= 0) {
                  parent.children.push(child);
                }
              });
            }); 
            
            //at whatever point in your code, you feel your
            // code has loaded all necessary data and/or
            // resolve your promise.
            deferred.resolve(parents);
        });
    });
    
  //return your promise to the user.
  return deferred.promise;
}


Tuesday, February 5, 2013

Angular JS - Scrolling To An Element By Id

So a question on StackOverflow recently was asking about how to scroll to an element by an anchor id, and it garnered some really hacky answers. They worked, but it seemed weird that Angular would force you to jump through hoops to manage scrolling. I thought the question was intriguing because it dealt with a potentially common scenario with a client-side routed application: How do I scroll to an element on the page?



Angular Already Has It

(I'm hoping for $kitchenSinkProvider in 2.x!)

Turns out that Angular already has a mechanism for this called $anchorScroll(). Unfortunately, it's poorly documented, and I had to actually view the source code on GitHub to figure out how to use it. So here's my attempt to remedy this: A quick run down of how to use $anchorScroll to scroll to the proper element after a routed request:

$anchorScroll works off of the hash value set in $location.hash(), so to use it dynamically, you'll need to first set $location.hash to something, then you'll need to call $anchorScroll().


Scrolling To An Element By ID With Routing


So presuming you've set up routing for your application module already in your .config function, I'm going to set up the scrolling mechanism in the application module's run function like so:

app.run(function($rootScope, $location, $anchorScroll, $routeParams) {
  $rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
    $location.hash($routeParams.scrollTo);
    $anchorScroll();  
  });
});

Pretty simple, right? What I did here is I subscribed to the $routeChangeSuccess event broadcast by the $routeProvider. Inside of that, I set the $location.hash to the value passed into $routeParams at the key scrollTo.

But where does that scrollTo value come from?

<a href="#/test/123/?scrollTo=foo">Test id=123, scroll to #foo</a>

The above link, assuming I have a route like "/test/:id" will route and then scroll to foo. It seems to be a little known thing about Angular that you can pass as many parameters as you like into $routeParams via a faux-querystring.

Anyhow, here is a demonstration on Plunker of the above technique.



Scrolling To An Element By ID Without Routing


Now something to note about $anchorScroll is that you don't have to use it just with routing, if that weren't obvious. You can inject it into any controller or directive and call it as you see fit. You just need to make sure you're setting the hash on Angular's $location.

For example, you could add an item to a list, and then scroll to it after it were added:


app.controller('MainCtrl', function($scope, $location, $anchorScroll) {
  var i = 1;
  
  $scope.items = [{ id: 1, name: 'Item 1' }];
  
  $scope.addItem = function (){
    i++;
    //add the item.
    $scope.items.push({ id: i, name: 'Item ' + i});
    //now scroll to it.
    $location.hash('item' + i);
    $anchorScroll();
  };
});


And here is demo of that on Plunker

Now, truth be told, it's a bit of fuzzy ground as to whether or not you should be using $anchorScroll in a controller like that. Since it's sort of "DOM manipulation" maybe it belongs in a directive... Then again, it never directly references the DOM does it? So it's most likely okay. It's down to a judgement call, and I always differ to whatever is easiest to maintain in those cases.


I Hope This Helps Someone


It's certainly not a well-documented feature. And in the sake of full (probably obvious) disclosure: I did of course contribute my answer on StackOverflow, I don't know or even care whether or not it's accepted, it's likely a better place than my blog for the answer to be so more people find it. I just want to make sure I got what I learned down somewhere I might think to look later, or that might help someone else.

If you found this and it helped you, I'd encourage you to head over the StackOverflow and answer just one question and help someone else. Pick a question you might not even know the answer to if you want to learn something new. The important thing is that we keep technology pushing forward by contributing, gaining knowledge, and innovating.

Monday, February 4, 2013

JavaScript - Scalar Promotion aka Hoisting

Scalar Promotion or Hoisting is a property of JavaScript that is often ignored but can cause some pretty crazy issues. (I like the term Scalar Promotion because it helps me fool people into thinking I'm smart and "Code Motion" sounds like I'm bullshitting too hard. Haha). To illustrate what it is and how it works, I'm going to show a few code examples. Take the following, very simple code for example:

(function() {
    var foo = 'abc',
          bar = 'xyz';
    console.log(foo + bar); //abcxyz
})();

The output of the above, as you might expect, will be abcxyz. Now lets have a look at what happens if we don't assign bar:


(function() {
    var foo = 'abc',
          bar;
    console.log(foo + bar); //abcundefined
})();


Now the output is going to be abcundefined. So what happens if we remove the declaration of bar?


(function() {
    var foo = 'abc';
    console.log(foo + bar); //ReferenceError!!!
})();


Now we get a ReferenceError, because bar was never declared. Well that makes sense, right? But to show you what Scalar Promotion is all about have a look at this.. we'll move the declaration of bar to somewhere below the console.log():

(function() {
    var foo = 'abc';
    console.log(foo + bar); //abcundefined again
    var bar;
})();

... and the result is abcundefined. Okay, what the tell right? Why does this behave that way? Scalar Promotion. Basically as a compiler optimization, all declarations are moved to the top of your code, so to speak. This is why you can use a function in code before you've declared it in javascript:

(function (){
  callMe();

  function callMe() {
    alert("I've been called!");
  }
})();


The reason this can become problematic is that JavaScript doesn't force you to declare your variables. So consider the following code:

// A Tale Of Two Foos
(function (){
    
    // an anonymous function to do something or other asynchronously
    // this could be anything, like an ajax callback for example.
    setTimeout(function (){
        
        //manipulate foo, but forget to declare it.
        for(var i = 0; i < 10; i++) {
          foo += 'x';   
        }
        
        // SORCERY?!!! 45xxxxxxxxxx?! 
        // this should just be ten  x's!
        console.log(foo);
    },0);
    
    /* ---
    assume some large amount of code here. So you don't 
    know/remember these two foos are in the same scope.
    --- */
    
    // declare foo and add some numbers to it.
    var foo = 0;
    for(var i = 0; i < 10; i++) {
        foo += i;
    };
    console.log(foo); //45
})();


Do you see what happened there? One little missed declaration and there's no error... just a bug. Generally the only way to avoid this is to try to declare your variables at the beginning of your function scope if possible/practical. Either way, be careful to declare you variables, kids!