Reputation: 95
I want to add a custom script that integrates into an existing Tag Manager dataLayer on a page. I need this script to be notified about new dataLayer pushes.
So whenever something on the page uses window.dataLayer.push
, my script should be informed about this.
Is there a way to add a custom dataLayer event listener to the Google Script API?
I am looking for something like
google_tag_manager.dataLayer.onPush(callback);
google_tag_manager.dataLayer.subscribers
seems to list how many dataLayer subscribers there are - but how can I add my own?
Upvotes: 5
Views: 17197
Reputation: 73
I had this exact same requirement, but I also wasn't allowed to directly modify the dataLayer
definition so couldn't use a Proxy. Happily Google have created a library that provides a set of helper functions tailored to the object: https://github.com/google/data-layer-helper
Deploy the script, then create a callback listener:
function listener(model, message) {
// Message has been pushed.
// The helper has merged it onto the model.
// Now use the message and the updated model to do something.
}
The added bonus here is you can use "listenToPast" to replay all events that were added to the dataLayer
before the code ran (also a requirement in my case).
const helper = new DataLayerHelper(dataLayer, {
listener: listener,
listenToPast: true,
});
Upvotes: 2
Reputation: 20924
JavaScript has a Proxy
object with which you can set traps whenever an operation is executed on an object. Arrays are also objects and can be used with proxies.
When calling the push
method on an array, a new value will be set
to the array. So setting a trap for the set
method should allow us to add behavior to the push
method.
In the trap, create a CustomEvent
event and dispatch it. You can name this event anything you want. Whenever a value has been added to the dataLayer
array, an event will be emitted. You can listen from every file to this event to act on whenever a value is added to the dataLayer
array.
With Reflect
we can make sure that the original behavior of the push
method is restored while keeping the added behavior.
window.dataLayer = window.dataLayer || new Proxy([], {
set: (obj, prop, value) => {
if (prop !== 'length') {
const pushEvent = new CustomEvent('datalayerpush', {
detail: value
});
window.dispatchEvent(pushEvent);
}
return Reflect.set(obj, prop, value);
}
});
window.addEventListener('datalayerpush', event => {
console.log(`Value pushed to dataLayer: ${JSON.stringify(event.detail, null, 2)}`);
});
window.dataLayer.push({
event: 'test'
});
Upvotes: 15
Reputation: 383
I'm not sure if you can do a 'native' implementation using the google_tag_manager object. You can, however, override the push method on the dataLayer array.
const originalPush = dataLayer.push
dataLayer.push = function(...args) {
// notify here
console.log('dataLayer.push was called');
originalPush(...args);
}
You can then implement some logic based on the Observer Pattern.
Below I show a VERY simple implementation, just for demonstration.
const originalPush = dataLayer.push
const dataLayerListeners = [];
dataLayer.push = function(...args) {
dataLayerListeners.forEach(listener => listener.notify())
originalPush(...args);
}
class DatalayerListener {
constructor(name) {
this.name = name;
}
notify(args) {
console.log("I'm listener "+this.name+" and I'm being notified that the dataLayer.push method was called");
}
}
const listener1 = new DatalayerListener('listener1');
const listener2 = new DatalayerListener('listener2');
dataLayerListeners.push(listener1);
dataLayerListeners.push(listener2);
Upvotes: 2