Form onSubmit and asynchronous operation


#1

Hi all!
I’m trying to call a function when the form is being submitted, so I added an “onFormSubmit” callback on my form’s embed code:

hbspt.forms.create({ portalId: '1669170', formId: '3af9a3b1-919e-4780-bd06-e0ef53ef5518', onFormSubmit: window.onFormSubmit });

the code is very simple, but since it involves a series of asynchronous operations we modified the onFormSubmit callback in order to resolve a Promise (to make sure that the asynchronous result has indeed been received).
During the code’s execution I have placed two alerts: the first when onFormSubmit has started, the other when the asynchronous method has been completed.

I tried this code on Chrome, Firefox and IE11 (!) with success (although it’s somewhat slower on IE); however, when running on Safari the second alert never gets printed (and its associated asynchronous operation aren’t executed).
Is there a way to prevent the HubSpot form to switch the page after submission, so that the onFormSubmit is fully executed?

You can find the test at http://webtest.services.thron.com/demo/hubspot/hubspot-form-test.html

Thank you,

Leonardo


#2

@leonardo.scattola I will try and get my hands on a macbook to test out safari. To answer your question though, your form is currently set up to display a thank you message instead of switching the page. The page only switches when you call it in your code to the response to the promise:

.then(function(result) {
		console.log("** login done!");
		window.location.href = '//marketing.thron.com/scopri-migliori-contenuti-da-produrre-costruisci-content-strategy-thron';
	});

#3

@pmanca Peter, yes, that is correct: I set up the form to show a message because I thought that this behaviour would allow me to perform the asynchronous tasks and wait them to terminate, and only then switch the page. All of the browsers, apart from Safari, correctly manage this situation and switch the page when the promise has been fulfilled.

Thank you,

Leonardo


#4

@leonardo.scattola it looks like you are missing a { after your else. Maybe safari is tripping up on that?

else
				  track("company", loginValue, contactName, function() {
					resolve("Ok!");
					// onLoginDone();
				  });
			   }

#5

Peter,
don’t be misleaded by the layout! I’ve checked the code with a JS code checker and there are no errors;

var tracker = _ta.initTracker('qaxthron');

function track(loginType, loginValue, contactName, callback) {
    tracker.loginAs(loginType, loginValue, contactName, callback);
};

function onFormSubmit() {
    alert("onFormSubmit");
    new Promise(function (resolve, reject) {
        var loginValue = $('[type="email"]').val();
        var contactName = $('[name="firstname"]').val() + ' ' + $('[name="lastname"]').val();
        var onFirstLoginEnd = function () {
            var loginValue = $('[name="company"]').val();
            if (!loginValue || loginValue.trim() == "") {
                alert("ok!");
                resolve("Ok!");
            } else {
                track("company", loginValue, contactName, function () {
                    resolve("Ok!");
                });
            }
        }
        track("email", loginValue, contactName, onFirstLoginEnd);
    }).then(function (result) {
        console.log("** login done!");
        window.location.href = '//marketing.thron.com/scopri-migliori-contenuti-da-produrre-costruisci-content-strategy-thron';
    });
}

hbspt.forms.create({
    portalId: '1669170',
    formId: '3af9a3b1-919e-4780-bd06-e0ef53ef5518',
    onFormSubmit: window.onFormSubmit
});

#6

@leonardo.scattola I pulled this from the page source from your page.

var tracker = _ta.initTracker('qaxthron');
	
	function track(loginType, loginValue, contactName, callback){
		tracker.loginAs(loginType, loginValue, contactName, callback);
	};
	
	function onFormSubmit() {
		alert("onFormSubmit");
		new Promise(function(resolve,reject) {
			  var loginValue = $('[type="email"]').val();
			   var contactName = $('[name="firstname"]').val() + ' ' + $('[name="lastname"]').val();
			   var onFirstLoginEnd = function(){
				  var loginValue = $('[name="company"]').val();
				   if(!loginValue || loginValue.trim() == "") {
						alert("ok!");
						resolve("Ok!");
					//onLoginDone();
					}
			else
				  track("company", loginValue, contactName, function() {
					resolve("Ok!");
					// onLoginDone();
				  });
			   }
			   track("email", loginValue, contactName, onFirstLoginEnd);
			}
		).then(function(result) {
			console.log("** login done!");
			window.location.href = '//marketing.thron.com/scopri-migliori-contenuti-da-produrre-costruisci-content-strategy-thron';
		});
	}
	
	hbspt.forms.create({
		portalId: '1669170',
		formId: '3af9a3b1-919e-4780-bd06-e0ef53ef5518',
		onFormSubmit: window.onFormSubmit
	});

This is slightly different code then what you pasted above. Have you uploaded your latest version of your code? The code above is missing an opening brace for your else statement.


#7

@pmanca i assure you that only the layout (apart from the two //onLoginDone(); comments) is different between the two versions; however, we just uploaded the latest version of the page on http://webtest.services.thron.com/demo/hubspot/hubspot-form-test.html .

Thank you,

Leonardo


#8

@leonardo.scattola Here is some food for thought. It looks like your then is executing before your onFirstLoginEnd function finishes. I ended up daisy chaining the function in an asynchronous pattern to match the rest of the code and it returned the second alert to me in safari. Let me know what you think of this below.

function onFormSubmit() {
		alert("onFormSubmit");
		new Promise(function (resolve, reject) {
			var loginValue = $('[type="email"]').val();
			var contactName = $('[name="firstname"]').val() + ' ' + $('[name="lastname"]').val();
			
		}).then(function (result) {
			var onFirstLoginEnd = function () {
				var loginValue = $('[name="company"]').val();
				if (!loginValue || loginValue.trim() == "") {
					alert("ok!");
					resolve("Ok!");
				} else {
					track("company", loginValue, contactName, function () {
						resolve("Ok!");
					});
				}
			}
			track("email", loginValue, contactName, onFirstLoginEnd);
			

		}).then(function (result) {
			console.log("** login done!");
			window.location.href = '//marketing.thron.com/scopri-migliori-contenuti-da-produrre-costruisci-content-strategy-thron';
		});
	}

#9

Peter,
nope… I can’t get your code to work: on our Safari machines the “**login done!” string never gets printed on the console.
I haven’t updated the test page yet, but all of our test confirm this behaviour.

Thank you again,

Leonardo


#10

@leonardo.scattola That is interesting as it worked on my safari machine. Also chrome and safari both use webkit as a back end so I would expect the two of them to act similar. Is it throwing any errors when you use the debugger in the dev tools?


#11

Peter,
I performed another round of tests; I’ve noticed that the two alerts indeed are printed, but a very long time (more than 1 minute) after the form has been submitted. This behaviour happens only on Safari; however, we feel that this isn’t acceptable, since we cannot make sure that the user stays on a page for such a long time.

Is it possible to have the submission code wait somehow for the onFormSubmit completion, for example by stopping the submission function (by means of preventDefault or in any other way)?

Thank you,

Leonardo


#12

@leonardo.scattola That is interesting that you guys see such long wait times on your safari machines. I did not experience that. What is your submission code? Looking at the code to your test page I only really see the onFormSubmit function.


#13

Peter,
the onFormSubmit calls a series of asynchronous function (the track ones) that are defined in our own tracking library.
Since they’re asynchronous, we wait for their completion by specifying a callback function:

track("email", loginValue, contactName, onFirstLoginEnd);

The onFirstLoginEnd function, in turn, performs another Ajax tracking which we await for; only after that those callbacks have been completed we resolve the promise and we mark the job as done (switching the location.href).

On Safari, what we experience is that the DOM of the page is changed well before that our promise has been resolved; usually the functions are performed in less than one second in total, but on Safari there is something that makes them last more than 20 seconds. Try the page in Chrome for example.

Because of this behaviour, I was wondering if there is a way to stop or delay the execution of the form submission in the HS code.

Regards,

Leonardo


#14

@leonardo.scattola Your best bet would be to have your own custom form. Then you can control those timing variables. When you are ready you can just make a post call to our contacts API. This will function the same exact way as the current form in place. The embed code is designed to try and make things easier and for those who have less experience coding. You obviously have experience coding so it should be rather painless for you to switch to a custom form. Then when all of your asynchronous functions have completed/resolved then you can push the info to hubspot via the contacts API. Here is a link to the documentation on it.

There are some examples of code in the contacts API as well depending on what language you use to make the post call.


#15

There are no errors in console


#16

@pmanca and @leonardo.scattola - Agreed that using a custom form is probably best, but rather than submitting the data to the Contacts API, you’ll want to use the Forms API (http://developers.hubspot.com/docs/methods/forms/submit_form). Contacts API requires authentication to make update calls, whereas the Forms API accepts submission data without auth (since it’s designed for open web forms, not backend integrations)


#17

@pmanca, we ultimately implemented this workflow (which we’re testing):

  • when the form has been created (onFormReady) we alter the input[type=submit] element in the form’s DOM to stop the event propagation
  • we perform our asynchronous tasks in a series of promises
  • on the completion of these promises we detach the on("click") listener and we force the form’s submission:

$(“input[type=submit]”, dom).unbind(‘click’).click();

This isn’t an optimal solution (since the HS form has not been sent yet when we call our webservices), but it will work in our case.

Thank you for your support,

Leonardo


#18

@leonardo.scattola I am glad you got a working copy.


#19

Leonardo, is there any more sample code you can provide here? I’m struggling to get the same result on my page.