On this publish, I’ll stroll you thru a tutorial on how you can create a Google Tag Supervisor extension. This extension will likely be a new listener, whose sole job is to hear for adjustments within the HTML and CSS markup on the web page.
The explanation I’m instructing you how you can create a DOM listener is easy. Ever so usually I come throughout individuals asking for assist, however they’re unable to the touch on-page code. Often the issue is magnified with type handlers, because the builders might need put in some customized jQuery type supervisor, as an example, which merely refuses to cooperate with GTM’s type listeners. That’s the reason you may wish to fireplace a GTM occasion when a sure message pops up on the display, for instance.
With a DOM listener, you may fireplace a GTM occasion each time one thing adjustments on the web page. Effectively, not each time. Really, on this instance you’re restricted to component insertion and attribute adjustments. A working use case may be type validation: if you wish to observe invalid types, possibly by sending the content material of the validation error message with an occasion, you may simply as properly create a DOM listener. This listener will then set off when an error message seems on the web page.
DISCLAIMER: To be truthful, I really feel fairly strongly about utilizing hacks equivalent to this to repair defective markup or an in any other case shoddy tag implementation. The primary thought behind this publish is to introduce a function of JavaScript which might alleviate a few of your tag administration pains. Nonetheless, in case you discover that you just want hacks such because the DOM listener to bypass improvement issues in your web site, I might strongly counsel that you just take this up together with your builders and attempt to provide you with an answer which works with GTM’s customary options.
X
The Simmer E-newsletter
Subscribe to the Simmer publication to get the most recent information and content material from Simo Ahava into your e mail inbox!
The premise
To create the DOM listener, I’ll leverage an API referred to as MutationObserver. This little piece of magic will create an observer object, which triggers each time a mutation takes place. This mutation can come in several styles and sizes, however for the needs of this information, I’ll hear for 2 sorts of mutations, for 2 sorts of use instances:
-
Node insertion – when a brand new
<span class="error">
is injected within the DOM -
CSS model change – when a beforehand hidden
<span class="error">
is displayed
So the primary use case is when your type injects a brand new SPAN component into the DOM upon an error. The script will examine if the injected node is actually the error message, and whether it is, it pushes a dataLayer occasion with the content material of the SPAN (the message itself).
The second use case is when an invalid type causes a hidden SPAN to seem, with the error message inside.
Listening for node insertion is a bit totally different than listening to an attribute change. A node insertion listener might be primed on any node on the DOM, which means you might have rather more to work with when it comes to flexibility. Listening for attribute adjustments requires you to pinpoint precisely which node you wish to observe, and the attribute change will likely be reported for that node solely.
Preparations
Listed below are the elements:
-
A web page the place a
<span class="error">
is both inserted or revealed with a CSS model change -
Customized HTML tag(s)
My take a look at web page code appears like this (I mixed each use instances into one right here):
<script>
perform addHTML() {
var myDiv = doc.getElementById("contents");
var newSpan = doc.createElement("span");
newSpan.className = "error";
newSpan.innerHTML = "This type contained errors";
myDiv.appendChild(newSpan);
}
perform changeCSS() {
var mySpan = doc.getElementsByClassName("error")[0];
mySpan.model.show = "block";
}
</script>
<a href="#" onClick="addHTML();">Add span with .innerHTML</a>
<a href="#" onClick="changeCSS();">Add span with CSS</a>
<div id="contents">
<span class="error" model="show: none;">This type contained errors</span>
</div>
Let’s simply rapidly go over this web page.
First, you might have two capabilities. The perform addHTML() will insert the next within the DIV#contents under:
<span class="error">This type contained errors</span>
The insertion is completed upon clicking a hyperlink whose textual content is “Add span with .innerHTML”.
Within the second perform, the SPAN.error is already within the DOM, but it surely’s been hidden with a show: none CSS command. When the hyperlink labelled “Add span with CSS” is clicked, this model directive will likely be modified to show: block.
That is simply my take a look at web page. Clearly you’ll have to navigate round your present implementation to make issues work.
Lastly, you’ll want your customized HTML magic. The subsequent two chapters will go over the tags and the code you’ll want to write down for them.
Case 1: node insertion
On this use case, a brand new node (<span class="error">
) is inserted right into a DIV on the web page. The markup on the web page appears one thing like this:
<script>
perform addHTML() {
var myDiv = doc.getElementById("contents");
var newSpan = doc.createElement("span");
newSpan.className = "error";
newSpan.innerHTML = "This type contained errors";
myDiv.appendChild(newSpan);
}
</script>
<a href="#" onClick="addHTML();">Add span with .innerHTML</a>
<div id="contents">
</div>
In order you may see, there’s an empty DIV (#contents), which is then appended with a brand new SPAN, created by the perform addHTML() which, in flip, waits for a click on occasion on the hyperlink on the web page.
Now, the subsequent step is to create the listener itself. You’ll want to make use of the MutationObserver API to hear for any node which is inserted into the noticed goal. The node itself might be on any degree within the DOM hierarchy, however I selected the DIV#contents to maintain issues easy. When a node is inserted, a dataLayer push is completed with a brand new GTM occasion and the textual content content material of the SPAN.
Right here’s what you Customized HTML Tag ought to appear like:
<script>
var contentDiv = doc.querySelector("#contents");
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(perform(mutations) {
mutations.forEach(perform(mutation) {
if(mutation.sort==="childList" && mutation.addedNodes[0].className==="error") {
dataLayer.push({'occasion': 'newErrorSpan', 'spanErrorMessage': mutation.addedNodes[0].innerHTML});
observer.disconnect();
}
});
});
var config = { attributes: true, childList: true, characterData: true }
observer.observe(contentDiv, config);
</script>
OK, OK, a lot of stuff occurring right here. Let’s undergo the script and see what it does. First, you create a reference to the DIV you may be listening to. I’m utilizing the querySelector() perform, as a result of it’s a pleasant technique to mix CSS selectors and JavaScript.
Subsequent, you create the MutationObserver itself by first tackling a recognized cross-browser subject with WebKit browsers. The observer listens for mutations of sort childList (a brand new baby node is inserted) and checks if the primary added node has CSS class “error”. You’ll have to change this code if the SPAN with the error will not be the primary node that your script inserts into the DOM.
If such a mutation is detected, a GTM occasion is pushed into dataLayer (newErrorSpan), and the error message contents are despatched as a knowledge layer variable as properly. Word that I take advantage of innerHTML to get the contents of the SPAN. In case your SPAN has HTML formatting inside, you may wish to use innerText as an alternative.
The disconnection implies that after this explicit mutation takes place, no additional mutations are listened for. So if somebody retains on pushing the “submit” button, the observer will shut down after the primary error. You may wish to take away this line if you wish to observe ALL the potential errors your customer propagates on the shape.
Lastly, I create a configuration for the MutationObserver and prime it on the DIV.
And that’s it for node insertion. If you happen to set this new listener to fireside on pages the place the SPAN with class “error” is created in a DIV with ID “contents”, a dataLayer.push() will happen each time the SPAN is inserted into the DOM. Strive it for your self!
Case 2: CSS change
On this case, you might have a hidden SPAN with the error message, which is then revealed when the shape validation fails. Right here’s what the HTML may appear like:
<script>
perform changeCSS() {
var mySpan = doc.querySelector(".error");
mySpan.model.show = "block";
}
</script>
<a href="#" onClick="changeCSS();">Add span with CSS</a>
<div id="contents">
<span class="error" model="show: none;">This type contained errors</span>
</div>
So I’ve a easy SPAN inside a DIV with the error message. That is initially set to show: none, however when the hyperlink is clicked, the show standing is modified to block.
As to your Customized HTML Tag, you’ll want one thing like this:
<script>
var spanError = doc.querySelector('.error');
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(perform(mutations) {
mutations.forEach(perform(mutation) {
if (mutation.sort==="attributes" && mutation.goal.model.show==="block") {
dataLayer.push({'error': 'modErrorSpan', 'spanErrorMessage': mutation.goal.innerHTML});
observer.disconnect();
}
});
});
var config = { attributes: true, childList: true, characterData: true }
observer.observe(spanError, config);
</script>
It’s fairly just like the earlier one however with one or two small adjustments. First, you’re not listening to the DIV, you’re listening to the precise node you realize would be the goal of the model change. That is essential, and it implies that it’s important to know precisely what the goal will likely be when creating this script.
Subsequent, within the observer itself, you’ll have to specify simply what the model change was. I used merely a change from show: none to show: block, however you might need one thing totally different in your code. So don’t neglect to alter the content material of the if-clause to match what the brand new model is.
The profit right here is that you just’re listening to only one single node, so there’s a efficiency increase. I’ve bought the observer.disconnect(); once more, however you may wish to take away that if you wish to ship occasions perpetually for every invalid click on of the submit button.
Don’t neglect to check.
Conclusions
This may look like a cool hack to you. In spite of everything, you’re listening for adjustments on the web page with out truly any web page refresh occurring! Additionally, you’re extending GTM’s default listeners so that you’re sort of like a Google engineer, proper?
Effectively, bear in mind what I stated within the disclaimer of this textual content. It is a hack, a circumvention, a band-aid, designed to beat issues together with your markup or your JavaScript. Having a customized type handler which doesn’t propagate a correct type submit occasion (which is required by GTM’s default type submit listener) is a bit suspect and reeks of unhealthy practices. So earlier than you resort to this DOM listener, be sure to exhaust all different, extra orthodox potentialities together with your builders.
Then once more, you may not want this to beat any improvement issues, however reasonably to enrich your present tag setup. In that case, go loopy! It’s a wonderful method so as to add extra flexibility to your tags. Do observe the cross-browser help, nevertheless. Assist will not be complete sufficient to warrant utilizing this listener as a firing rule for some business-critical tag.