3

For a bunch of anchor tags on our sites we send an event to Google Analytics in order to track the users behaviour, right now I am using the following code (triggered on click):

event.preventDefault();
ga(tracker, 'event', category, action, label, value, { 'hitCallback':
    function(){
        window.location = url;
    }
}); 

This works fine but there is one issue, some users (myself included) tend to middle-mouse / command+click most links in order to open them in a new tab. This obviously wont work with the above script.

I was wondering if there is something like event.triggerDefault() that will give the control of the event back to the browser, or if I really have to build something that will detect middlemouse / command clicks from the user.

Sidenote: We use native javascript

Kokos
  • 9,051
  • 5
  • 27
  • 44
  • Hi sorry dont have time to write out my idea but you can track the middle button click see: http://stackoverflow.com/questions/1795734/triggering-onclick-event-using-middle-click and thinking you can just add a if statement to figure out what mouse button they are using to click. – NicoM May 29 '14 at 22:15
  • This sadly won't work because in order to detect command+clicks I'd have to set global variables when keydown / keyupping the command button or something, and would provide issues across different operating systems. – Kokos May 30 '14 at 08:47
  • So as it turns out you don't have to set global variables, because the event holds properties that tell you about this (event.metaKey). But it would still mean rewriting browser functionality in Javascript which is very bad practice and has a high chance of breaking upon browser updates. – Kokos Jun 03 '14 at 09:15

2 Answers2

2

With the help of How to trigger an event after using event.preventDefault() and How to clone or re-dispatch DOM events? I came up with the following solution:

<script>
var anchor = document.getElementById('anchor');
anchor.addEventListener('click', function(e){
    if(e.eventHandled) return;
    e.preventDefault();

    window.alert('Javascripts');

    var clonedEvent = new e.constructor(e.type, e);
    clonedEvent.initEvent(e.type, true, false);
    clonedEvent.eventHandled = true;
    anchor.dispatchEvent(clonedEvent);
});
</script>
<a href="http://www.google.com/" id="anchor">Google</a>

Now when command+clicking the link you first receive the alert, and afterwards are sent to a new tab.

Jsfiddle: http://jsfiddle.net/8NRJY/1/ (Note that jsfiddle wont change urls if you do a normal click, but this works fine outside of jsfiddle)

Now all there's left is making this cross browser compatible, and inserting the google tracking of course (the dispatchEvent would be inside the callback).

Edit: Here is the cross-browser (IE8+ at least) compatible version.

The first functions should be part of your library if you're working in native javascript.

<script>
var addEventListener = function(elem, eventName, handler, useCapture) {
    if (elem!=null) {
        if (elem.addEventListener) {
            if (useCapture===true||useCapture===false) {
                elem.addEventListener(eventName, handler, useCapture);
            }
            else {
                elem.addEventListener(eventName, handler);
            }
        } else {
            elem.attachEvent('on' + eventName, function(evt) {              
                evt = evt || window.event;
                evt.target = evt.target || evt.srcElement;
                handler(evt);
            });
        }
    }
};

var onReady = function (fn) {
    if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', fn);
    } else {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState === 'interactive' || document.readyState === 'complete'){
                fn();
            }
        });
    }
};

var fireEvent = function(el, event){
    if(document.createEvent){
        var clonedEvent = new event.constructor(event.type, event);
        clonedEvent.initEvent(event.type, true, false);
        el.dispatchEvent(clonedEvent);
    }else if(document.createEventObject){
        var clonedEvent = document.createEventObject();
        el.fireEvent('on'+event.type, clonedEvent);
    }
};

onReady(function(){
    var anchor = document.getElementById('anchor');
    addEventListener(anchor, 'click', function(e){
        if(!anchor.eventDispatched){
            e.preventDefault ? e.preventDefault() : e.returnValue = false;
            anchor.eventDispatched = true;
            fireEvent(anchor, e);
        }else{
            anchor.eventDispatched = false;
            e.returnValue = true;
        }
    });
});
</script>
<a id="anchor" href="http://www.google.com">Test</a>  

Edit 2: Fixing this to work with Google Analytics is proving to be a much tougher task than I thought.

In modern browsers, it works great right off the bat. In IE8 there's only a single event at a time (stored in window.event), which means that Google's callback overrides that, which means I can't re-fire the original event. I'm trying various methods of cloning the event to make it work, but so far no success.

I hate you IE8.

Edit 3: I've given up on trying to make this work in IE8.

Edit 4: As it turns out, Chrome blocks the new window as a popup, because the event is triggered after a callback (even though its the original user click event).

Community
  • 1
  • 1
Kokos
  • 9,051
  • 5
  • 27
  • 44
1

If you want to track user navigation across internal links on your site using Google analytics, the following might help.

  1. Store the Google Analytics (GA) event data in a cookie, but don't send the GA event just yet.
  2. Let the DOM event's default behaviour execute.
  3. On the next page, read the cookie, look for queued GA events, and send them to analytics.

From what I've experienced, the cookie is set instantaneously before leaving the page.

To make sure the GA events correspond to the right page in your reports, you should send the events to GA doing something like this:

var currentPage = window.location.pathname;
var previousPage = document.referrer.replace(/^[^:]+:\/\/[^/]+/, '').replace(/#.*/, '');

ga('set', 'page', previousPage);
ga(tracker, 'event', category, action, label, value, { 
    'hitCallback': function(){
        ga('set', 'page', currentPage);
    },
    'nonInteraction': 1
});

The callback restores the page value for subsequent analytics requests. Non-interaction makes sure the event doesn't affect your bounce rate.

  • So I tried this, however when opening a couple of tabs quickly after each other (a likely situation) you get race conditions with reading / setting the cookie that holds the event queue. This means a lot of times events will be sent more than once. – Kokos Jun 03 '14 at 09:12
  • Good point. You could add a server-sided call to check for race conditions, but that's probably not something you want to be doing. – Sebastiaan Moeys Jun 07 '14 at 10:50