Attention: The Marketo Community will undergo scheduled maintenance on Tuesday, August 20th between 10-11 PM PDT. During this time, the Community and its content will not be accessible. We apologize for any inconvenience this may cause.
In a recent post, you learned that having multiple form embeds in the same page, with loadForm
called from more than one domain, causes fatal errors.
Those errors can break any form on the page, depending on load order. (I didn’t mention this explicitly before, but when multiple forms are injected via GTM or another async mechanism, you can’t predict the order — meaning you can’t even predict which form(s) will fail on a given pageview.)
The solution is to load all forms from the same domain, preferably your LP domain.[1]
But there’s one case when you can’t do that: when you’re deliberately loading embeds from different Marketo instances. Not just different aliases for the same instance, but totally different instances, like one for B2B and one for B2C.
In this case, you can’t simply standardize on one domain. But what you can do is force the Forms 2.0 loader to create a separate instance of MktoForms2
for each domain. This will in turn create a separate IFRAME for each instance of the library, so they can submit side-by-side.
MktoForms2
SxSThis task is superficially simple: you’d think you could delete the global MktoForms2
before each embed, so the library will think it hasn’t been loaded yet. But that simple method doesn’t work in practice, due to a pesky problem with polyfills (such as the Input Mask and Date plugins).
So I ended up having to write this just-short-of-too-crazy Forms 2.0 Instance Manager. Pretty proud of it, gotta admit... good to flex the ol’ Getter and Setter muscles.
First, include the core function:
/**
* Enable side-by-side Marketo Forms 2.0 libraries from different domains
* @author Sanford Whiteman
* @version v1.0 2021-12-30
* @copyright © 2021 Sanford Whiteman
* @license Hippocratic 3.0: This license must appear with all reproductions of this software.
*
*/
function MktoForms2PerInstanceManager(instanceBaseURLs,iter){
let instances = new Map();
/* evergreen browsers can use an unthrown Error, IE 11 needs throw */
function genStack(){
let tempError = new Error(),
stack = tempError.stack;
if (stack) {
return stack;
} else {
try {
throw tempError;
} catch (error) {
return error.stack;
}
}
}
/* no one said finding the source URL wouldn't be sloppy, but it works */
function getInstanceURLFromStack(stack){
return instanceBaseURLs.filter(function(url){
return stack.indexOf(url) != -1;
})[0];
}
Object.defineProperty(window, "MktoForms2", {
configurable: true,
get: function() {
let stack = genStack(),
instanceKey = getInstanceURLFromStack(stack);
return instances.get(instanceKey);
},
set: function(library) {
let stack = genStack(),
instanceKey = getInstanceURLFromStack(stack);
instances.set(instanceKey, library)
}
})
return instances;
}
Then create an Instance Manager object, passing it your different instances’ URLs:
/* add all possible base URLs of your different instances */
let instanceURLs = [ "//pages.example.com", "//explore.example.net" ];
/* create the instance manager */
let MktoForms2Instances = new MktoForms2PerInstanceManager(instanceURLs);
To load forms, add events, and so on, first get()
the appropriate instance from the Manager. The methods are otherwise the same stuff from the Forms 2.0 API:
<form id="mktoForm_1449"></form>
<script src="//pages.example.com/js/forms2/js/forms2.js"></script>
<script>
/* use an instance */
MktoForms2Instances.get("//pages.example.com").loadForm("//pages.example.com", "410-XOR-673", 1449);
</script>
<form id="mktoForm_1379"></form>
<form id="mktoForm_787"></form>
<script src="//explore.example.net/js/forms2/js/forms2.js"></script>
<script>
/* use another instance */
MktoForms2Instances.get("//explore.example.net").loadForm("//explore.example.net", "410-XOR-673", 1379);
MktoForms2Instances.get("//explore.example.net").loadForm("//explore.example.net", "410-XOR-673", 787);
</script>
You can add events to all forms on all instances by forEach()
-ing over the instances:
MktoForms2Instances.forEach(function(MktoForms2Library) {
MktoForms2Library.whenReady(function(mktoForm) {
mktoForm.onSubmit(function(mktoForm) {
console.log("Marketo form " + mktoForm.getId() + " on the move")
});
});
});
forEach
to get every instance automatically
Or target a specific instance + form only if it’s present:
if (MktoForms2Instances.has("//explore.example.net")) {
MktoForms2Instances.get("//explore.example.net").whenReady(function(mktoForm) {
if(mktoForm.getId() == 787) {
mktoForm.addHiddenFields({
Email: "teknkl+test0001@email.invalid",
Letter_Date__c: "2022-02-01"
});
}
});
}
[1] You could load them all from the app-*
domain, but then they’ll be blocked when Tracking Protection is on. So kill two birds with one stone and standardize on your LP domain.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.