Search code examples
javascripttypescriptwebpackaurelia

How can I access the Google Analytics dataLayer Variable in Aurelia?


I'm using the webpack with typescript combo for aurelia and want to know how I can push to the global dataLayer variable provided by google analytics in Aurelia classes?

When I try to log it I get: Cannot find name 'dataLayer’.

but when I log it in the console of my browser, dataLayer exists

Any idea on how I can expose it?

console.log(window.dataLayer);

@inject(AppState, AuthService, SetupGuide, Endpoint.of('api'), 
DialogService, EventAggregator, Router)
export class Smoke {}

I know with webpack you can use shimming via:

new webpack.ProvidePlugin({
    $: "jquery",
    jQuery: "jquery",
    "window.jQuery": "jquery"
})

Is this possible also with the dataLayer variable? I need to be able to update the dataLayer variable so I can setup Enhanced Ecommerce tracking.

UPDATE: I've also tried:

(<any>window).dataLayer = (<any>window).dataLayer || [];

Does throw a type error: "Error: Can't resolve 'dataLayer'"

I need to be able to get access to the google analytics global variable and am not sure why this doesn’t work or how to expose it for ES6.

I'm using webpack and typescript and have added it to my index.ejs as follows:

<body aurelia-app="main">
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-okoko" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>
   (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
   new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
       j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
   'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
   })(window,document,'script','dataLayer','GTM-ookok');
</script> 

UPDATE 2:

There is no script tag that loads the app. Aurelia binds to body element. This is my entire index.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title><%- htmlWebpackPlugin.options.metadata.title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <base href="/">
    <link rel="apple-touch-icon" href="apple-touch-icon.png?v=2">
    <link rel="icon" href="/favicon.png?v=5" />
    <meta name="theme-color" content="#34274f">
    <meta name="msapplication-navbutton-color" content="#34274f">
    <meta name="apple-mobile-web-app-status-bar-style" content="#34274f">
    <link rel="manifest" href="/manifest.json">  
    <% if (htmlWebpackPlugin.options.metadata.ENV === 'local') { %>
    <link rel='stylesheet' href='./src/main.css' type='text/css'>
     <% } %>
    <!-- imported CSS are concatenated and added automatically -->
  </head>
  <body aurelia-app="main">
    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-ookok" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <script>
       (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
       new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
       j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=false;j.src=
       'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
       })(window,document,'script','dataLayer','GTM-ookok');
    </script>
  </body>
</html>

Sample code that uses the variable:

import { Router } from 'aurelia-router';
import {AppState} from '../../resources/global/appState';

@inject(AppState, Router)
export class Sample {
   attached(){
     console.log(dataLayer);
   }
}

Solution

  • Adjust your code as follows. Update your main.ts file so that it looks like

    import {Aurelia} from 'aurelia-framework';
    
    export function configure(aurelia: Aurelia) {
      // ...
    }
    
    window.dataLayer = window.dataLayer || [];
    
    declare global {
      interface Window {
        // TODO: replace this with a more specific type based on usage
        dataLayer: any[];
      }
    }
    

    NOTE: The Aurelia specific code in the snippet above exits only to provide context. This answer is answer is also not specific to Webpack but rather applies to any TypeScript project using modules.

    From here on you just access it by referencing window.dataLayer. The initialization code as well as the global declaration could be moved into a separate file and you could wrap it up in a service which acts as a proxy for the global if you wish to.