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.
Called by the BOOMR.init() method to configure the SPA plugin. There is only one configurable option:
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.
This should always return true
as EventListener
s
for MutationObserver
and route change
will trigger
independent to the onLoad
event.
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
ConfigurationTo 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.
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
APIis_complete()
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)
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
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.
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.
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.