0

We need to track clicks in some buttons inside a body owned by a ng-controller.

The elements are not created by directives, before the angular initialzation, the HTML is something like:

<html>
    <body ng-controller="SomeController" ng-init="someFunction()">
        <a id="myButtonId" name="somNameOfInteres" ng-click="doSomething()">My Link</a>
    </body>
</html>

We use Google Tag Manager for attaching some jQuery and non-jQuery events in links and buttons inside the body:

jQuery('a[name="somNameOfInteres"]').on('mousedown', function () {
  // send some events to Google Analytics
});

// or

document.getElementById('myButtonId').addEventListener('mousedown', function () {
  // send some events to Google Analytics
});

In both cases, the ng-init function seems to remove all event listeners in all elements inside the html body.

I have tried to put my event listener inside:

angular.element(document).ready(function() {
    jQuery('a[name="somNameOfInteres"]').on('mousedown', function () {
      // send some events to Google Analytics
    });
});

But this didn't work either.

How can I add these event listeners without they get removed by Angular?

Thiago Melo
  • 1,157
  • 1
  • 14
  • 31
  • *ng-init function* - what's this? I'm not sure what you're trying to do, and the problem may be specific to your case. Are these buttons created by directives? There's no evidence that the listeners were removed; they could never exist. Any way, this should be done in Angular app and not GTM, because app DOM isn't static and tends to change. *to put my event listener inside* - where? The question lacks http://stackoverflow.com/help/mcve . – Estus Flask Feb 18 '18 at 22:40
  • @estus thanks for the advice. I tried to make some improvement. About ng-init: https://docs.angularjs.org/api/ng/directive/ngInit – Thiago Melo Feb 19 '18 at 00:09
  • There's no someFunction in the code you've posted. Btw, ng-init is antipattern. If this code is expected to run on initialization, it should be called in SomeController. Any way, yes, listeners should be set up by application (likely SomeController) and not GTM. – Estus Flask Feb 19 '18 at 00:24
  • @estus the `someFunction` does not make something related to the elements, something in the very Angular removes the listeners. I see what you are saying, maybe that is the answer I seek. I don't work in the development team, but in the Web Analytics team, all I can do is JavaScript through GTM. What I need is to hear from somebody that understand Angular something like "yes, Angular overrides the eventlisteners, there is nothing you can make about, ask the development team to make this for you" – Thiago Melo Feb 19 '18 at 00:31
  • 1
    It doesn't override event listeners. In fact, there's no way in JS to remove a listener that was set with addEventListener and *anonymous* function. You may have some race conditions, or the element was recompiled and doesn't exist (although it does in the code you've posted). The problem may depend on when exactly this GTM code runs (GTM has [weird undocumented lifecycle](https://stackoverflow.com/questions/41655123/gtm-randomly-skips-initial-pageview-in-single-page-app)). – Estus Flask Feb 19 '18 at 00:57
  • 1
    Depending on this, you may want to postpone it even further, e.g. with `angular.element(window).on('load', ..)` instead of `angular.element(docoment).ready(...)`, see https://stackoverflow.com/a/44682211/3731501 . If this doesn't help, try it to postpone even further with setTimeout. A proper solution is make dev team do this (things like angulartics-google-tag-manager exist exactly to do this the right way), or at least ask them to emit global event that the page was rendered (this part may be more tricky because most times this moment isn't determined). – Estus Flask Feb 19 '18 at 01:01
  • After you say, I tried the `angular.element(window)` alternative, but it didn't work either. Right now, it is working through a setTimeout, but who knows how long it takes depending on the internet and device, it is making me crazy. I really liked your idea about the global event, if it works, it will be easier than angulartics. Thanks to the resources you gave, I feel that angulartics is the only correct way. Thank you. If you could compile this in an answer, I think it answers my question ;) – Thiago Melo Feb 19 '18 at 01:12
  • 1
    You can start with debugging if `document.getElementById('myButtonId')` is really there at the moment when the script runs, and then check if it stays the same after 5-10 seconds (save element ref to global variable and do `===` comparison with fresh document.getElementById('myButtonId') ). Considering that page initialization is async (otherwise I would expect `ready` to work already), there's a good chance that global event is impractical.or impossible (it always depends on the app). Glad if it helped. I'll try to come up with the answer later. – Estus Flask Feb 19 '18 at 01:20
  • Adding jQuery events via GTM does not make them GTM events, so I think the google-tag-manager-tag is misapplied here. – Eike Pierstorff Feb 19 '18 at 08:26
  • The race conditions may be a real problem. It would help if you clarify how exactly you're sending data to Google Analytics. – Дмитро Булах Feb 19 '18 at 08:55
  • If you're making dataLayer.push make sure you're not overriding dataLayer object in the race conditions. You'll most probably need `var dataLayer = window.dataLayer || [] ; dataLayer.push({'event': 'name of interest'})` – Дмитро Булах Feb 19 '18 at 08:56

0 Answers0