RAC
RAC

Reputation: 514

AngularJS and Google Analytics

I am trying to dynamically change my GA tracking ID (UA-XXXXXXX-X) depending on which environment the page is being viewed on but I can't seem to find a truly "angular" way to do it. I am using Angulartics but I can't get the base GA code to run which is needed before Angulartics can do anything. If I just put the GA code at the bottom of the page it works as expected but that isn't very Angular like and it still does not allow me to dynamically set the GA ID.

I have tried creating a directive but the tracking code doesn't seem to be run when put inside a directive's controller. I have created a controller that gets the environment from a rest call and then assigns a GA code based on the environment returned but when I run the directive it runs to early and the GA code doesn't fire or it fires while the tracking ID is still undefined. I also tried putting the GA code into the directives template but for some reason the code doesn't fire at all when placed inside script tags inside the ngAnalytics.html template even though i can see it is being correctly added to the page once the dom is loaded. I am new to angular so I know there is a solution but I am not seeing it. My directive is below:

angular.module('ngAnalytics', [])
.directive('ngAnalytics', function( servicesSrvc) {
    return {
        restrict: 'A',
        templateUrl: 'js/directives/ngAnalytics.html',
        controller: ['$scope', function($scope) {
            $scope.trackingID;
            $scope.getEnvDetails = function() {
                var currentEnv = servicesSrvc.getEnv();
                var env;
                currentEnv.then(function(data) {
                    env = JSON.stringify(data.environment);
                    switch(env)
                {
                    case 'local':
                        $scope.trackingID = 'disabled'; // DEV
                        break;
                    case 'dev':
                        $scope.trackingID = 'UA-XXX-X'; // DEV
                        break;
                    ...
                        $scope.trackingID = 'UA-XXX-X'; // Default to dev
                }
                (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
                    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
                    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
                })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
                ga('create', $scope.trackingID, { 'cookieDomain': 'none' }); // For localhost testing
                //ga('create', $scope.trackingID, 'test.com'); // For dev, qa, prod etc...
                //ga('send', 'pageview'); // MUST BE DISABLED when using Angulartics
            });
        }

    }],
    link: function(scope, iElement, iAttrs, ctrl) {

    }
}
});

Upvotes: 5

Views: 3543

Answers (1)

m59
m59

Reputation: 43795

I might be misunderstanding your issue. It sounds like a general problem of directive architecture. Is something like this what you're looking for? Live demo (click).

<div analytics="trackingId"></div>

JavaScript:

var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope) {
  //set this however you want, the directive doesn't care - or you can move this into the directive if you want
  //$scope.trackingId = 'UA-XXX-X';
  $scope.trackingId = 'disabled';
});

app.directive('analytics', function() {
  return {
    restrict: 'A',
    scope: {
      id: '=analytics'
    },
    link: function(scope, iElement, iAttrs) {
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

      scope.$watch('id', function(newId, oldId) {
        if (newId) {
          console.log(newId);
          ga('create', scope.id, { 'cookieDomain': 'none' });
        }
      });
    }
  };
});

The important part here is:

scope.$watch('id', function(newId, oldId) {
  if (newId) {
    ga('create', scope.id, { 'cookieDomain': 'none' });
  }
});

which is saying to run the function only if there is a value for scope.id and the function will run again if the value is set or changed. I'm not sure what you're doing with servicesSrvc, but you could use that service to set scope.id from the controller or in the directive itself, either way, and if you've already setup the $watch, the function will run when you determine the value for scope.id. My answer is based on your comment that the function would run when the value was undefined. This is how you avoid that.

Update

Since you're still having issues understand the process, I have created another demo with some console.logs to guide you. Demo here (click).

var app = angular.module('myApp', []);

app.factory('myService', function($q, $timeout) {
  var myService = {
    getId: function() {
      var deferred = $q.defer();

      console.log('getting id');
      $timeout(function() {
        //deferred.resolve('UA-XXX-X');
        deferred.resolve('disabled');
      }, 2000);

      return deferred.promise;
    }
  };
  return myService;
});

app.directive('analytics', function(myService) {
  return {
    restrict: 'A',
    link: function(scope, iElement, iAttrs) {
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

      var id;
      scope.$watch(
        function() {
          return id; 
        }, 
        function(newId, oldId) {
          if (newId) {
            console.log('watch is calling function');
            ga('create', newId, { 'cookieDomain': 'none' });
          }
        }
      );

      myService.getId().then(function(response) {
        id = response;
        console.log('id set to ' +response);
      });
    }
  };
});

Upvotes: 8

Related Questions