ngHelper-Toolbar: Now supports secondary actions & dividers

The $toolbar service is a great helper when it comes to building toolbars in AngularJS applications. The new version 0.0.3 allows you to handle new secondary actions, as shown here in the Azure Cost Monitor application:

secondary-actions

The secondary action can be defined in the addItem function similar to all other options the API supports:

$toolbar.addItem(‘childContract, contract, null, null, true, ‘/report/1234’, null, ‘activeContract’, ‘fa-trash’, function () {                   $scope.removeContract(contract);
});

Making the menu more user-friendly can be achieved by adding dividers in the structure. When using the special menu title “DIVIDER” the system will use this in the menu structure as divider:

$toolbar.addItem(‘user.divider’, ‘DIVIDER’, null, null, true, null, null, ‘user’);

The new navigation infrastructure of the Azure Cost Monitor is using the $toolbar service from the ngHelper-Toolbar project. We hope this feature makes it simple to maintain your toolbars. Any questions, wishes or ideas? Try the issue button on the GitHub page or contact the author via this blog.

ngHelperAirbrake: Airbrake for AngularJS

Airbrake is a well known exception tracker which is used from thousands of users. A cool thing is that the Airbrake team also supports browser based javascript exception. Integrating these kind of javascript code gives AngularJS developers sometime a headache. The newest member of the ngHelper collection, the ngHelperAirbrake component makes it super simple and easy to integrate Airbrake in an existing AngularJS application.

It’s a bower component and works well with scaffolding tools like Yeoman. Installing the component is possible with the following command line:

bower install ng-helper-airbrake –save

After that the component is registered in the bower.json of the project. Moving up the dependency entry to the position right after the inclusion of angular ensures that the Airbrake-Shim is loaded as early as possible when doing a full page reload.

“dependencies”: {
“angular”: “~1.3.8”,
“ng-helper-airbrake”: “~0.1.0”,

ngHelperAirbrake offers the $airbrake angular service which allows to configure the different Airbrake settings. The documentation at our project page describes how to set the right configuration: https://github.com/ngHelper/ngHelperAirbrake

After configuring the project everything works as expected and Airbrake receives exception from the AngularJS application.

SEO – Is your Azure WebSites hosted AngularJS App ready for Google :-)

Every AngularJS application is just a website which is generated by executing javascript. The google crawler and also other crawlers are not able to collect information from these sites. To handle this problem a couple of services like AjaxSnapshots or Prerender.io are trying to fill the gap. Basically these services are generating a snapshot of a website without any javascript in it. Whenever the search engine visits the page, the system delivers a plain html page without any javascript. Many technical details on how search engines crawl a page can be found here. Users who are hosting on Azure WebSites and trying to use this kind of pre-rendering tools may stuck with some configuration issues.

The required rewrite rules for the web.conf are written very fast or can be found in the AjaxSnapshots documentation:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="AjaxSnapshotsProxy" stopProcessing="true">
                    <!-- test all requests -->
                    <match url="(.*)" />
                    <conditions trackAllCaptures="true">
                        <!-- only proxy requests with an _escaped_fragment_ query parameter -->
                        <add input="{QUERY_STRING}" pattern="(.*_escaped_fragment_=.*)" />
                        <!-- used to capture the scheme/protocol for use in the rewrite below --> 
                        <add input="{CACHE_URL}" pattern="^(https?://)" />
                    </conditions>
                    <!-- send the request to the AjaxSnapshots service -->
                    <action type="Rewrite" 
                    url="http://api.ajaxsnapshots.com/makeSnapshot?url={UrlEncode:{C:2}{HTTP_HOST}:{SERVER_PORT}{UNENCODED_URL}}&amp;apikey=<YOUR API KEY>" 
                    logRewrittenUrl="true" appendQueryString="false" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

An example for Prerender.io can be found here.

After applying the web.conf to the website, the browser returns directly a 404 which means that the website behind the target URI is wrong. This is because Azure Websites enabled the redirect module but rewriting URLs to external target requires a revers proxy module additionally. This module which is part of the application request routing in IIS is not activated in Azure WebSites by default. Thanks to the following nice trick it’s possible to use the reverse proxy module also in Azure WebSites:

http://ruslany.net/2014/05/using-azure-web-site-as-a-reverse-proxy/

As usual all technical frameworks, components or services described in this blog are used in production for several weeks in different applications, e.g. the Azure Cost Monitor. These steps should help to get every AngularJS application ready for google and other bots when the site is hosted on Azure WebSites.

Cache Fighters Part 3 – A real life example combined with grunt-ng-constant

In the last two parts of this article series, the caching behaviour of AngularJS applications was described and a solution for all issues in a typical app was delivered.
The last part now is focussed on developing a real life example which demonstrates the authors favourite solution.

When following this tutorial Yeoman should be installed on the machine. In addition the angular generator of Yeoman is required.

Generate a simple application
Yeoman initially generates a skeleton of a AngularJS application. Firing the following command starts the generation process:

yo angular testapp

All this should be done in a directory called testapp because Yeoman is not generating a subdirectory automatically. During the process Yeoman asks some details which need to be answered as follows:

yeoman-answers

Integrate ngHelperDynamicTemplateLoader
The dynamic template loader is the base component in AngularJS applications to handle the caching issues for views and partials. It can be installed with the following command line:

bower install ng-helper-dynamic-template-loader –save

After that the http request interceptors need to be registered which can be done by adding the following lines in the configuration section of the application, typically implemented in the app.js file:

'use strict';

angular
  .module('testappApp', [
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch',
    'ngHelperDynamicTemplateLoader'
  ])
  .config(function ($routeProvider, $dynamicTemplateLoaderProvider) {

    $dynamicTemplateLoaderProvider.registerInterceptors();

    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  });

Generate a deployment UUID
The custom caching strategy will be based on a deployment UUID. Whenever the deployment UUID is changed, the system will change the URI for the views & partials. There are two additional modules which are required. grunt-ng-constant is responsible for generating an individual build-related configuration file. The node-uuid module is able to generate a new deployment UUID whenever it is required. The modules can be installed via npm as follows:

npm install grunt-ng-constant –save-dev
npm install node-uuid –save-dev

After that a new grunt task is available and the following grunt configuration needs to be generated in the configuration file. The config section is building an app-env.js file during every build which contains the needed deployment UUID:

ngconstant: {
  options: {
    dest: '<%= yeoman.app %>/scripts/app-env.js',
    wrap: '"use strict";\n\n {%= __ngModule %}',
    name: 'app.env'
  },
  dist: {
    constants: {
      envDeployment: {
        deploymentUUID: uuid.v4()
      }
    }
  },
  serve: {
    constants: {
      envDeployment: {
        deploymentUUID: uuid.v4()
      }
    }
  }

}

Don’t forget to require the uuid module somewhere at the start of the existing grunt file:

var uuid = require('node-uuid');

Last but not least the grunt-ng-constant task needs to be added in the build-, test- and serve-tasks to ensure that a config file is generated:

grunt.registerTask('build', [
  'clean:dist',
  'ngconstant:dist',
grunt.task.run([
  'clean:server',
  'ngconstant:serve',

grunt.registerTask('test', [
  'clean:server',
  'ngconstant:serve',

When executing the configuration a module which is called “app.env” is generated and needs to be added in the dependency list of the AngularJS application:

angular
  .module('testappApp', [
    'app.env',

Additionally the “app-env.js” needs to be registered in the index.html so that it will be loaded during application start:

<!-- build:js({.tmp,app}) scripts/scripts.js -->
<script src="scripts/app-env.js"></script>

Build a custom caching strategy
Everything is settled for the deploymentUUID based caching strategy. In the ngHelperDynamicTemplateLoader every caching strategy is implemented as a specific service.

yo angular:service CustomTemplateCaching

The following service should be added to the application to ensure that the generated deploymentUUID is used:

‘use strict’;

angular.module(‘testappApp’).service(‘CustomTemplateCaching’, [‘envDeployment’, function(envDeployment) {
var self = this;
self.processRequest = function(requestConfig) {
if (requestConfig.url.indexOf(‘?’) === -1) {
requestConfig.url = requestConfig.url + ‘?v=’ + envDeployment.deploymentUUID;
} else {
requestConfig.url = requestConfig.url + ‘&v=’ + envDeployment.deploymentUUID;
}
return requestConfig;
}
}]);

The service can be assigned to the template loader as a caching strategy in the run region of the application

.run([ '$dynamicTemplateLoader', 'CustomTemplateCaching', function($dynamicTemplateLoader, CustomTemplateCaching) {
  $dynamicTemplateLoader.setCachingStrategyService(CustomTemplateCaching);
}]);

Finally after starting the application with the command:

grunt serve

the browser will load all of the templates with a special version parameter in the url. The version parameter contains the deploymentUUID which means the system is using the cache as long as nothing has changed but after an update the system is using a new uncached version of the views.

caching

The illustrated caching provider can be improved when using a grunt task which is building hash keys for every HTML file. The hash keys can then be used in the request so that HTML files would be reloaded from the server when the specific view has changed which is a more granularly approach.

The solution stays with the eager loading approach of views & partials which works good in bigger applications. For smaller and midsize applications compiling everything in a single javascript file feels ok as well.

This article should help to solve the views and partial caching issues in all AngularJS applications. The described approach is successfully used in production applications, e.g. Azure Cost Monitor over the last weeks. The sample application developed in this article can be found here.

Cache Fighters Part 2 – How to handle eager loaded partials/views

The previous part of this article series described the general behaviour of an AngularJS app when it comes to web caching. Using Yeoman and the generated grunt tasks solved many topics on the existing caching list. This article is focused on the different strategies to handle views & partials.

Views & partials are HTML files which are loaded from the AngularJS application during the first use. Whenever a user navigates to a new sub site or is using a new widget which was never loaded, AngularJS triggers an AJAX call to load the corresponding html file. Inline templates which are part of the javascript files are an exception of course.

Like every HTTP request the AJAX call can be cached from a web cache like the browser as well. Yeoman has out of the box no grunt task onboard to rename this files which would prevent caching.
But there a two options to solve this problem:

The first solution ensures that all external templates are combined to one single file as inline templates. During this process a grunt task generates one single javascript file, which contains all the views & partials. The grunt-angular-templates module allows to implement this behaviour which solves the caching issue in combination with the javascript minification as described in the last article at full length.

The second option is to implement a similar behaviour to what Yeomans grunt tasks ensure for javascript files. Whenever the view or partial is updated it should get a different name and would be reloaded from the server and not from the cache. This lets the application use as much cached files as possible and only reloads over the network when something is changed.

For the Azure Cost Monitor, I wrote a component called ngHelperDynamicTemplateLoader which totally implements this behaviour. The component is implementing a standard interceptor to add a new version parameter to every view loading AJAX call. The default caching strategie just adds a timestamp every time the view is loaded which means no caching at all. Voila, that is what we wanted to achieve.

In the next part of this article series I’m going to describe a real life example. This example will use grunt-ng-constant to generate context which can be used in a custom caching strategy.

Do you know any other options to deal with this topic? Then please leave a comment to kick off a short discussion about it.

Cache Fighters Part 1 – Caching behaviour of AngularJS Apps

Every website, which also means every AngularJS app, needs to deal with different web caches.  This can be different proxy servers or even the browser cache as a very extensive cache.

Caching, on the one hand, can be very important because it helps to run any application as fast as possible, but on the other hand it can cause different problems when e.g. updating an published app. That’s what I had to deal with, when I prepared the user interface update of the Azure Cost Monitor – an AngularJS app for cloud cost management.

So this article describes how an AngularJS app behaves under the influence of different caches and gives an outlook to different strategies how to deal with potential problems.

An AngularJS app is technically a normal website which uses a lot of AJAX calls. This means that the app contains following elements:

  • index.html (the main entry point)
  • Views/Partials
  • Javascripts
  • Stylesheets
  • Media-Assets

There are different caching headers as described here. As long as the author of an app doesn’t intervene, all files are cached, which means that it’s hardly predictable when the browser ever tries to load the different assets from the server again.

Last-Modified is a “weak” caching header in that the browser applies a heuristic to determine whether to fetch the item from cache or not. (The heuristics are different among different browsers.)

This caching behaviour is good because the application should of course be of good performance. Loading big files from the cache is certainly faster then downloading them from a remote server – but when the application gets updated different caching problems might occur and for these problems some special handling is required.

Many people around are using Yeoman as a scaffolding application. The awesome AngularJS generator in Yeoman is generating a Gruntfile which compiles the AngularJS application. Folks coming from C/C++ could wonder what compiling means in this context. Here it just means preparing the different assets to be hosted on a production server. Normally this includes dealing with a couple of caching issues. Yeoman uglifies and minifies the javascripts, stylesheets, images and html files. During this process all javascripts, stylesheets and images get a hash-based new unique name. This is the first trick to prevent caching by a web cache like the browser. Keep in mind: Cached ressources are adressed by absolute URLs.

So back to the list above, the caching behaviour of the following three elements are solved:

  • Javascripts
  • Stylesheets
  • Media-Assets

Pretty cool 😉 but how to handle the rest?

The index.html should never be cached in an AngularJS application because this file contains all references to stylesheets and javascripts. Would a web cache, like the browser, cache this file, it would become very difficult to update a published app. In Azure Websites e.g., the preconfigured IIS takes care of this via correct Cache Headers. This ensures that the AngularJS application can be updated at any time.

Last but not least, on the list above the Views/Partials in AngularJS are left. These are HTML files, which are loaded via Ajax calls when they are needed. The next part of this article series will describe how to handle them by using caching as much as possible but preventing it in different cases. So stay tuned…

ngHelperUserVoice: AngularJS service for the UserVoice API

UserVoice is a Saas platform that offers different customer engagement tools i.e. feedback- and ticketing tools. A modern web application written in AngularJS, should always offer the user the possibility to open a ticket whenever it is needed. One solution to do so is to use the UserVoice Contact widget, but if you would prefer to use an API, for instance if your contact form has special styles that you don’t want to loose, here is the solution:

The new ngHelper component ngHelperUserVoice is a lightweight angular service for opening tickets in UserVoice. The component follows the angular way of building single page applications and allows the configuration of the module via provider and offers a standard service:

$uservoice.openTicket(“NAME”, “EMAIL”, “SUBJECT”, “MESSAGE”).then(function(ticketId) {
  alert(“Ticket with id: ” + ticketId + ” created”);
}).catch(function(error) {
  alert(“Error: ” + error);
});

This component makes it super simple to interact with the UserVoice API. If you like the component feel free to add other features, I will accept push requests as fast as possible.