GTM Callback firing multiple times - google-analytics

I've followed the Google docs to add GTM tags to my site. For some reason the call back is firing 3 times, however, I only have this tag on the page.
window.dataLayer.push({
'event': 'add_expense',
'eventCallback': function () {
alert('wtf');
}
});
Anyone have any clues on why this may be?

It could be you have multiple GTM containers on the page, including plugins. You can check to see if the callback is being passed different containers ids:
'eventCallback': function (id) {
alert(id);
}

This happened to me after enabling GA4 in the page. Seems like it is using same container and rules as GTM and caused callbacks to fire twice. My solution:
const buildGtmCallback = (callback) => {
//GA4 is also a container, so need to fire callbacks only once, for GTM container
//GA4 containerId starts with G-
return (containerId) => {
if (containerId.startsWith("GTM-") && typeof callback === "function") {
callback();
}
}
}
And then whatever you wish to be fired only once:
window.dataLayer.push({
'event': 'add_expense',
'eventCallback': buildGtmCallback(function () {
alert('wtf');
})
});
This solution will also work if you have multiple GTM containers by modifying containerId.startsWith("GTM-") and replace “GTM-“ with the container ID you wish the event to fire for. However in that case you won’t be sure event was fired for both containers, just that one

Related

wpcf7 and GTM event listener issue

I have a Tag set up in GTM, custom html like this;
<script>
document.addEventListener( 'wpcf7submit', function( event ) {
dataLayer.push({
'event' : 'wpcf7successfulsubmit',
'CF7formID' : event.detail.contactFormId
});
}, false );
</script>
Doesn't work. Not at all. So I put a script on the page.
var wpcf7Elm = document.querySelector( '.wpcf7' );
wpcf7Elm.addEventListener( 'wpcf7submit', function( event ) {
dataLayer.push({
'event' : 'wpcf7successfulsubmit',
'CF7formID' : event.detail.contactFormId
});
}, false );
from a basic example on contactform7.com. This, in GTM preview, triggers fine. The first time it triggers the tag once, the 2nd and subsequent times it triggers twice (implying that both my script and the GTM tag are firing). Guessing at a problem with the event bubbling up. I put the specific selector wpcf7Elm into the tag's custom html but this doesn't work - like the first example.
I have no problem with running from a script but the problem is firing the tag twice so that the analytics shows two events. I would like to use GTM but at the moment the only solution I can see is to go back to on page scripts.
Can anyone suggest what I might be doing wrong? Just to note that I have disabled all plugins and that I am using, on a different page, a wpcf7 event listener successfully (from a script on the page) to perform a presentation function.

MeteorJS - List item Not updating after implementing publish / subscribe and methods / calls

Ok so this is a little weird...
I got these methods on server side ...
Meteor.publish('todos', function () {
return Todos.find({userId: this.userId},{sort:{createdAt:-1}});
});
Meteor.methods({
editTodo: function(todoId) {
Todos.update(todoId, {$set: {checked: !this.checked}});
}
});
And here is the invocation on client side ....
Template.list.helpers({
todos: function(){
Meteor.subscribe('todos');
return Todos.find({});
}
});
Template.list.events({
"click .toggle-check": function(){
Meteor.call('editTodo',this._id);
}});
The problem is that when the click on ".toggle-check" occurs ... the 'checked' boolean is triggered on but never comes off .... is this.checked (in {checked: !this.checked}) not referring to field immediately read from the collection?
Or maybe I am implementing something wrong when subscribing to the data?
Please help!
I believe the issue relates to the registration of the subscription as you suggested - more specifically that your Meteor.subscribe() is being called from within a Template.helpers function.
Try moving your subscription to an earlier page or template event such as Template.body.onCreated() or Template.list.onCreated() (depending on your requirements).
There is a good example in the Meteor documentation: https://www.meteor.com/tutorials/blaze/publish-and-subscribe (see section 10.3).

Is there any way to insert a callback before/after a templates context is updated?

I'm aware of Template.onRendered, however I have the need to destroy and setup some plugins that act on the dom when the actual context is updated.
So saying I have content template, I'd need something similar to the following:
Template.content.onBeforeChange(function () {
$(".editor").editable("destroy");
});
Template.content.onAfterChange(function () {
$(".editor").editable();
});
Is there any current way I can achieve this with the existing Template api?
You should be able to detect a context change within a template autorun by looking at currentData like this:
Template.content.onRendered(function() {
this.autorun(function() {
if (Template.currentData()) {
// the context just changed - insert code here
}
});
});
I'm unclear if that works for your particular case because this technique only gets you the equivalent of onAfterChange.

how to properly bind jquery ui behaviors in meteor?

I am trying to create a group of draggable DOM objects using jQuery UI's .draggable() that are populated through Meteor subscriptions. The code I came up with looks like
Meteor.subscribe('those_absent', function() {
$( "li.ui-draggable" ).draggable( { revert: "invalid" } );
});
Meteor.subscribe('those_present', function() {
$( "li.ui-draggable" ).draggable( { revert: "invalid" } );
});
These correspond with some Meteor.publish() calls, so that any time the collection changes, the .draggable() behaviour will be attached. At least, that was my intention.
However, it only works once - once one of these <li>'s has been dragged and dropped, then they are no longer draggable at all.
When the objects are dropped, I'm firing a custom event that is attached to the Template for the item like so
$( "#c_absent .inner-drop" ).droppable({
drop: function( event, ui ) {
ui.draggable.trigger('inout.leave');
}
});
Template.loftie_detail.events = {
'inout.leave': function (e) {
Lofties.update({_id:this._id}, {$set: {present: 'N' }});
}
};
So, my thinking is that this change to the collection on drop should propagate through the pub/sub process and re-run the .draggable() line above. But it doesn't seem to.
The complete code for this can be seen here https://github.com/sbeam/in-out/blob/master/client/inout.js and the app is live at http://inout.meteor.com/ (there are some other probably unrelated issues with items randomly losing values or disappearing from the UI altogether)
So if my understanding of how pub/sub works in Meteor is off, it would be good to know. Or is there a more efficient way to achieve this UI behavior binding that works without it?
The way I have implemented this in my apps is with the method shown by #lashleigh.
I have a template event that listens using code like this :
Template.myDraggableItem.events({
'mouseover .workItem' : function() {
$(this._id).draggable();
}
});
Then I listen for the dragstop like this.
$('body').on('dragstop', '.myDraggableItem', function (e) {
// Update the collection with the new position
};
You can see the app that's using this code at aduno.meteor.com

FullCalendar is inserting duplicate events even when removing all events

FullCalendar is working great apart from 1 issue I'm having.
The monthview div which loads a calendar in monthview mode, seems to show duplicate holidays loaded in. This happens when I add an event, and then call my calendar bind function, which basically runs the code below.
Has anyone else had a similar issue? It looks like 'removeEvents' function is working ok against the data feed which comes from an internal database, but seems to leave the google dates. When the addEventSource is called, it's adding the same events again.
var googleUkHolidaysFeed = {
url: 'http://www.google.com/calendar/feeds/uk__en%40holiday.calendar.google.com/public/basic',
cache: true,
color: "green"
};
$.getJSON(url, {}, function (data) {
$('#dayview').fullCalendar('removeEvents');
$('#dayview').fullCalendar('addEventSource', data);
if ($("#monthview")[0]) {
$('#monthview').fullCalendar('removeEvents');
$('#monthview').fullCalendar('addEventSource', data);
$('#monthview').fullCalendar('addEventSource', googleUkHolidaysFeed);
}
});
I resolved this issue myself. The 'removeEvents' has to be called followed by 'removeEventSource' like so:
('data' is json array of events provided by the app, 'googleCalendarUkHolidayFeed' is the url feed from google).
var googleCalendarUkHolidayFeed = {
url: "http://www.google.com/calendar/feeds/bla..."
}
$('#dayview').fullCalendar('removeEvents');
$('#dayview').fullCalendar('addEventSource', data);
if ($("#monthview")[0]) {
// remove events and re-add event source to reflect search/non-search
$('#monthview').fullCalendar('removeEvents');
$('#monthview').fullCalendar('removeEventSource', googleCalendarUkHolidayFeed);
$('#monthview').fullCalendar('removeEventSource', data);
$('#monthview').fullCalendar('addEventSource', googleCalendarUkHolidayFeed);
$('#monthview').fullCalendar('addEventSource', data);
}

Resources