All Docs | Index

Single Page Application Plugin APIs

Note: These plugins require the AutoXHR and SPA Plugins to be included in your build of Boomerang.

The Single Page Application (SPA) Plugins are designed to support Boomerang in cases where SPAs are used on the page and therefore the page's onload event doesn't matter. In those cases Boomerang will send Beacons when a route change event appears.

Between the start and end of the route changes Boomerang will monitor the DOM for MutationObserver events and XHR requests. If those happen we will automatically assume that they are relevant to the route change event.

Note: It is not advisable to provide support for multiple SPA Plugins in the same boomerang build.

Note: If you are unsure if your version of a specific SPA is supported by the plugins presented here please refer to the compatibillity list below.

The code and examples described in this document apply for the following frameworks:

init() Configuration

Each plugin requires to be either enabled or disabled in boomerang's init() function of BoomerangJS. As mentioned above you should only compile one SPA plugin plus its depenedncies into your Boomerang release. This avoids breaking Boomerang by running multiple SPA-plugins at the same time.

init(oConfig)

Called by the BOOMR.init() method to configure the SPA plugin. There is only one configurable option:

enabled
[required] Set this to true only for the SPA you wish to work with in your project or application.
BOOMR.init({
	// AngularJS
	Angular: {							
				enabled: true				
	}								
	// Ember.js
	Ember: {							
				enabled: true				
	},								
	// Backbone.js
	Backbone: {							
				enabled: true				
	},								
	autorun: false,							
	// Disable XHR instrumentation as this is auto-enabled by the SPA-plugins 
	instrument_xhr: false						
});

NOTE: It is advisable to tell Boomerang not to start automatically by setting the autorun flag to false.

NOTE: If you are not using a SPA-Framework but rely mostly on XMLHttpRequests to build your site, you can leave out the SPA plugin configuration and just enable instrument_xhr to measure your site.

is_complete()

This should always return true as EventListeners for MutationObserver and route change will trigger independent to the onLoad event.

hook()

Hook specific to the SPA. Please refer to the SPA-Framework specific documentation below on which parameters to fill this with

AngularJS Configuration

For AngularJS it is necessary to hook Boomerang into the application from the run Callback.

In your AngularJS Application or module add this to the run() callback:

// If boomerang is loaded to late to watch the first route change happen 
// toggle hadRouteChange to true using the routeChangeStart callback.
// This will tell the plugin to fire a beacon immediately as it gets
// initialized and not wait for a routeChange event.
var hadRouteChange = false;
$rootScope.$on("$routeChangeStart", function() {
  hadRouteChange = true;
});
function hookAngularBoomerang() {
  if (window.BOOMR && BOOMR.version) {
    if (BOOMR.plugins && BOOMR.plugins.Angular) {
// pass your $rootScope object and the aforementioned hadRoueChange variable to
// the hook to both make sure we are listening for route changes and check whether
// or not we we're on time
      BOOMR.plugins.Angular.hook($rootScope, hadRouteChange);
    }
    return true;
  }
}
// If we hooked in correctly we would return true if not we wait for the onBoomerangLoaded event
// to fire and try again as we can be sure then that Boomerang has arrived in the page
if (!hookAngularBoomerang()) {
  if (document.addEventListener) {
    document.addEventListener("onBoomerangLoaded", hookAngularBoomerang);
  } else if (document.attachEvent) {
    document.attachEvent("onpropertychange", function(e) {
      e = e || window.event;
      if (e && e.propertyName === "onBoomerangLoaded") {
        hookAngularBoomerang();
      }
    });
  }
}

Internally the AngularJS plugin will hook into the $routeChangeStart event and set timers for when the request for the route change started. After that — once the routeChange has happend — the MutationObserver that has been set up will realize that everything has been loaded, give itself another second to make sure it hasn't missed any final changes and then send a beacon out.

Backbone.js Configuration

For Backbone.js we need to be hooked into the application prior to the first Backbone.history.start() call in the application. Failing that (eg. Boomerang was too late to initialize) a variable called hadRouteChange passed to the Backbone.js hook should be set to true.

Given these rules you can add the following to your Router definition (Backbone.Router.extend({})) in the init() function.

var hadRouteChange = false;
app.Router.on("route", function() {
  hadRouteChange = true;
});
function hookBackboneBoomerang() {
  if (window.BOOMR && BOOMR.version) {
    if (BOOMR.plugins && BOOMR.plugins.Backbone) {
      BOOMR.plugins.Backbone.hook(app.Router, hadRouteChange);
    }
    return true;
  }
}

if (!hookBackboneBoomerang()) {
  if (document.addEventListener) {
    document.addEventListener("onBoomerangLoaded", hookBackboneBoomerang);
  } else if (document.attachEvent) {
    document.attachEvent("onpropertychange", function(e) {
      e = e || window.event;
      if (e && e.propertyName === "onBoomerangLoaded") {
        hookBackboneBoomerang();
      }
    });
  }
}

Ember.js Configuration

To make Ember.js work with Boomerang it is necessary to pass the Application itself to the Boomerang plugin.

In your Ember.js Application add this to the route() callback:

function hookEmberBoomerang() {
  if (window.BOOMR && BOOMR.version) {
    if (BOOMR.plugins && BOOMR.plugins.Ember) {
      BOOMR.plugins.Ember.hook(App);
    }
    return true;
  }
}

if (!hookEmberBoomerang()) {
  if (document.addEventListener) {
    document.addEventListener("onBoomerangLoaded", hookEmberBoomerang);
  }
  else if (document.attachEvent) {
    document.attachEvent("onpropertychange", function(e) {
      e = e || window.event;
      if (e && e.propertyName === "onBoomerangLoaded") {
        hookEmberBoomerang();
      }
    });
  }
}

Just like the AngularJS/Backbone.js SPA plugin we intend to hook into the application as early as possible. However the difference here lies in the point we hook into. The Ember.js plugins hook() function will either reopen the already set ApplicationRoute or set the Ember.js applications ApplicationRoute by extend()ing the Ember.Route Class. We will hook into the applications activate function and willTransition event.

Custom SPA Support

If you use a SPA framework that isn't one of the above or want to write your own integration into your setup, we allow you to do so by using the underlying code used by the pre-built plugins to hook in.

BOOMR.plugins.SPA API

is_complete()
Since the SPA plugin is just another BOOMR plugin we have to implement is_complete. It shoudl always return true as it isn't bound to the normal boomerang lifecycle and does not have to complete for the classic onload beacon to fire.
init(config)
As is the case with is_complete() we have to implement init() to configure the SPA plugin. Here we configure the SPA plugins ability to enable or disable AutoXHR on demand after the first route change has happend.
register

Since there can be multiple SPA frameworks compiled into your version of boomerang each SPA plugin should register itself by calling register with the name of the plugin as a string argument. This will make sure, that when you call BOOMR.init() with the option to enable the SPA plugin of your choice AutoXHR will acknowledge that and disable itself until re-enabled by the SPA plugin after the first route change has finished.

This means your SPA plugin should register itself early on in the evaluation of your plugins code. Even before defining the plugin itself. Here is an example:

(function(){
	// If our plugin is already defined just skip re-evaluating.
	// same goes for if BOOMR.plugins.SPA is not defined 
	if (BOOMR.plugins.MySPAPlugin || typeof BOOMR.plugins.SPA === "undefined") {
		return;
	}

	// register as a SPA plugin
	BOOMR.plugins.SPA.register("MySPAPlugin");

	BOOMR.plugins.MySPAPlugin = {
		/* Your SPA Code */
	};
}());
supported_frameworks
Used internally in the AutoXHR plugin to check if one of the registered SPA plugins has been enabled.
hook(hadRouteChange)

Called by a SPA plugin once it has hooked into the framework of choice. The boolean argument hadRouteChange is used to flag if Boomerang has loaded late or not. This will decide if AutoXHR will be enabled right away or only when the first route_change call has happend. hook will set the flag http.initiator to spa to flag that the next beacon comes from a SPA event.

route_change

As soon as the first route_change event, triggered by the SPA, will be initiated this function should be called enablinge listening for any DOM changes (using MutationObserver) and XHR calls required to finish the route change. This will make sure that all required assets for the route_change have been fetched. Since this is a SPA event AutoXHR will wait an entire second for everything to settle.

last_location(url)

To make sure that the sent beacon at the end of the route_change event will also contain the refferal URL we came from, last_location documents this URL to put into the beacon.

SPA-Plugin compatibillity:

The SPA plugins were tested and used in production environments with the following versions of each SPA-Framework:

Compatible versions of each framework should work as intended.

Browser compatibility considerations

As these plugins require AutoXHR and the availabilltiy of MutationObserver it is advisable to have a polyfill for browsers where the framework may be supported but MutationObserver isn't. See the MutationObserver supported browser list. If you are required to support browsers that don't support MutationObserver, consider adding a polyfill.