Sunday, October 12, 2014

AngularJS - Async module loading at Runtime with ocLazyLoad

I finally got to a point in my AngularJS-based app where I'm implementing a "modular" plug-and-play type interface that could eventually grow to consist of integration with dozens of 3rd party applications.  Ideally, each 3rd party integration is its own module (or multiple modules).  Because of the need for scalability, an absolute requirement was that each module could be loaded asynchronously at runtime on an as-needed basis.

Without giving it much upfront thought, and considering the app was already architected in an AMD style using RequireJS, I thought it this would be a no brainer.  Just load the modules at runtime and voila, it would all just work.  That was stupid thinking...  In Angular, every dependency needs to trickle down to the main app module to be loaded prior to the main app instantiation.  In this way, it's not "possible" to load a new module at runtime by pulling down the Javascript at a later point and instantiating it, unless you're open to loading an entirely new sub application.  This is not something I wanted to do.

In comes ocLazyLoad, our savior for asynchronously loading angular js modules, and as luck would have it, it works with RequireJS straight out of the box with one minor configuration update.  Once I stumbled upon this sweet library, things went pretty quick.

Because I am using RequireJS, I am loading my main app with something like this:

angular.bootstrap(document, 'main')

This requires that I do a little bit of configuration to make ocLazyLoad happy.

First off (and this applies to everyone, regardless of use of RequireJS), you need to load the ocLazyLoad library and reference it in your main app module.

For those using requirejs, it might look something like this:

You'll notice two things: A) I reference my "mainApp" module name in the "loadedModules" array, and B) I specify "require" as the asyncLoader.  If you don't use requirejs, you need not have that.

Once this is complete, it's quite easy to load a new module asynchronously:

You'll see in the code above that I have an file called "asyncmodule", this looks like any other module you might create, and contains a directive. Then I have another file called "parentDirective.js". This contains a directive that gets loaded into the "mainApp" module created earlier. It's assumed this directive file would be referenced directly from mainApp.js. As well, this directive lists "$ocLazyLoad" as a dependency so it can be used at run time.

 Inside of the parentDirective, a user clicks a button that invoked a call to the "loadAsyncModule" method. This method then invokes $ocLazy.load() method, passing in the name of the async module and the path to the file. In return, it receives a promise which listens for the successful loading of the module. Once this is complete, you can now use your new module (or directive within the module, as is the case here) as you would any other. In my case, in the success callback of the promise, I then go ahead and load a template dynamically (http://thewebbler.blogspot.com/2014/10/angularjs-be-careful-dynamically.html) that references the "async-directive" as an attribute.  It all works pretty well.

Saturday, October 11, 2014

AngularJS - Be careful dynamically setting content using $compile



I was recently working on a directive that dynamically generated new content at runtime based on user interaction, and the new content sometimes contained other directives that needed to be recognized. To get this to be properly "angularized", I used the $compile() method manually. Tada, the new content and sub directives were all linked perfectly. However, I noticed whenever I replaced that content subsequent times, my sub directives were not getting destroyed...a huge concern for memory leaks, and it also meant that all of the content that didn't have a sub-directive, well this would not be destroyed properly either. So I started digging into it...


Here's my explanation:

When creating a directive, imagine you have a situation where, based on certain conditions, you want to call render one existing template or another. Some solutions use dynamic templates via "ng-include" in the template declaration itself, but this isn't great for responding to user interaction. So instead, we get to straight down to it and invoke the $compile() method.


The $compile() method takes a template, turns that template into a function, and returns the function. That function is then invoked against a scope. Now, here's where we can get into trouble. Take an example:


link: function(scope, element, attrs) {

    //Some user interaction
    scope.changeContent(newTemplate) {


    //Retrieve the template from $templateCache
    var tpl = $templateCache.get(newTemplate);

    //Generate the angularized HTML code, attached to the scope
    var html = $compile(tpl)(scope);

    //Replace the contents of the current directive element with the new HTML
    element.empty().append(html);


    scope.on('$destroy', function() {
        //Cleanup code here

    });
}


This is all good now, but if our directive is something that will be many times throughout the app, we need to be careful with this, because this will cause a memory leak on subsequent calls to the "changeContent" method. The reason is that the template function created with the $compile() method is now attached to your scope, and this scope is not going to be destroyed before running it again.


Luckily, there is an easy fix. You create an isolated child scope from the current scope, keep a reference to it, and then you can destroy the child scope before creating a new one.
Here's how you might do it:


link: function(scope, element, attrs) {
    var childScope = null;

    //Some user interaction
    scope.changeContent(newTemplate) {

        //Destroy the old child scope
        if (childScope != null) {
           childScope.$destroy();
        }

    //Create  a new isolated scope that inherits from our current scope
    childScope = scope.$new();

    //Retrieve the template from $templateCache
    var tpl = $templateCache.get(newTemplate);

    //Generate the angularized HTML code, attached to the new child scope
    var html = $compile(tpl)(childScope);

    //Replace the contents of the current directive element with the new HTML
    element.empty().append(html);


    scope.on('$destroy', function() {
        //Cleanup code here

        // This is not necessary as the child scope will be destroyed when this scope is destroyed, BUT, it makes me feel better to see it happening.

        if (childScope != null) {
            childScope.$destroy();
            childScope = null;
        }

    });
}

Saturday, October 4, 2014

Softlayer Object Storage (OpenStack SWIFT) Temporary URLs - How-To in NodeJS!

I've implemented Amazon S3 in the past without a problem.  Documentation is a breeze to get through, making implementation super-easy.  However, having recently moved from AWS to SoftLayer for hosting, I decided to switch Object Storage from S3 to Softlayer Object Storage.

Softlayer makes it incredibly easy to set up Object Storage on a pay-as-you-go system, just like S3. And you get a reduced rate bandwidth to Object Storage from within a SoftLayer Hosted instance.  Cool.

Now to the implementation.  When you start poking around on the Object Storage documentation at SoftLayers website, you quickly find yourself at the OpenStack documentation for OpenStack v1.0.  No Problem here, but make sure you note that SoftLayer is still using the v1.0 OpenStack API.  Now, Like most people might, I wanted to get right to it and upload a file to Softlayer system.  In my case, I'm running a web app with a NodeJS server.  As such, I find the SDK's page on the OpenStack Documentation  and am pointed to a sweet Github project pkgcloud.

Pkgcloud makes it really easy to upload a file from a multi-part form post request in.  It goes something like this:

Loading ....


In the above code,  username, password, authUrl are all provided under the "Account Credentials" area on SoftLayer's website.  I am simply pulling them from a config file.  However, you should note the "version: 1" and "useServiceCatalog: false".  Those are required to tell pkgcloud that you want to use OpenStack v1.0 API (required by SoftLayer).  They currently default to v2.0, and don't officially support v1.0 at all right now.  Therefore, you will want to use my forked copy of pkgcloud, until this pull request, #330, is merged into the master branch. (EDIT 10/7/2014 - Pull Request #330 was merged into master, you can now reference pkgcloud Github repo, but NPM has no yet been updated.  Look for milestone 1.0 to be released on NPM before installing)

In Addition, the "Stream" variable is simply my "request" object passed from my RESTful API Endpoint.  Container is the Object Storage container I want to place the file into, and the resourceKey is the full populated path to the file.  E.g. "path/to/my/file.txt".  Voila.  Once this is done, file.txt is now at /container/path/to/my/.

That is easy (thanks pkgcloud).  But now we get to the meat of the issue.  Your web-based client wants to now retrieve the file that was just uploaded.  To do this, you use secure temporary URL's.  These are URL's that must be generated on the server and include some nice features to ensure your files aren't exposed to the public.  Lots of systems do this in a similar fashion, like S3.

With OpenStack Swift though, it's not that easy.  First you need to set some temporary URL Keys on your OpenStack account, before you can generate the Temporary URL, and to do this, you need some info that SoftLayer doesn't expose through their website.  Specifically, you need your X-Auth-Token and your X-Storage-Url.  Luckily, these are easy to retrieve, something like:

Loading ....


In the above, I make a GET request to the Softlayer Authentication URL provided by SoftLayer in the Account Credentials for the storage account, it would be something like https://dal05.objectstorage.softlayer.net/auth/v1.0/.  I set the 'X-Auth-User' and 'X-Auth-Key' headers to the credentials provided by Softlayer.

If all goes well, I get a 200 response and can retrieve by X-Auth-Token and X-Storage-Url from the response headers, as shown above.

Now that I have these, I can move forward setting the Temporary URL Keys.  These are completely arbitrary string values you can make up and set to anything you like, I believe of any length you like.  I use a random series of 30 alphanumeric charaters.  As well, there are two of them, allowing for key rotation over time, whereby one key is always valid while the other key is getting changed.

To set these keys, you would do:

Loading ....


If you get a 204 statusCode, you're good to go.

Now that we've set our keys, we can finally create our temporary URL for the file in the container and at the path (resourceKey) you need.  Here is an example method:

Loading ...

The above code is a little more complex, because I'm checking to determine if I already have my Storage URL required to make the call.  If I don't, I request it from SoftLayer and then request the signed URL again.

Hopefully that helps anyone who is new to SoftLayer object storage, whether using NodeJS or any other language.


Tuesday, April 1, 2014

IIS Dynamic content compression

Let me start of and say I don't care for blogging too much.  However, like so many others in the world of Tech, its important to give back and help others overcome the same problems you've already wasted hours on yourself, and it is a great way to keep a log of all of one's travails.

To the meat of it:

We have an XHR service (REST services) heavy Javascript / HTML5 app written with many technologies, best known are .NET, BackboneJS, RequireJS.

Quite a while ago I set up dynamic compression on our IIS 7 staging environment server.  It was pointed out not long ago that I had never done so in our production environment, thus our JSON requests were being sent and received without gzip compression.

Of course I went to correct this mistake today and couldn't remember how I had set it up in the first place. I scanned the blogs and modified the web.config and and looked under the "compression" setting for the website in IIS, nothing seems to work.  Then I remembered this was an App config settings, not a website specific settings.

So, here's how I managed it:

1) On your IIS 7 server, open up Internet Information Services Manager.

2) At the root level, Double click on the top-most machine to access the IIS settings for the server.

3) This should bring you to a window looking like this:


4) Click on "Configuration Editor" (shown here in the bottom left, under "Management" section

5) Under the "section" dropdown, select "system.webServer," and then "httpCompression":



6) Ensure your settings look approximately like these:

7) Importantly, expand the section labeled "dynamicTypes", you should ensure your JSON types are included, by adding "application/json" and "application/json; charset=utf-8".

8) Once that's all set, navigate to your website item in IIS, click on the "compression" tab and ensure both static and dynamic compression options are selected.

9) Now recycle the App Pool associated with your website and you should be good to.

Happy gzipping.