This is legacy code.
I'm working on a project where we're using iframes to simulate AJAX.
Basically, we're using the target attribute to submit the <form> in an iframe, resulting in the request not opening a new tab. Also, we echo a <script></script> in the response from the PHP, and the result is executed since it populates the iframe.
Here's an example of such <form> :
<form id="form_to_submit" method="POST" action="ajax/createUser" target="iframe_name">
<input type="text" name="input_to_send">
<button type="button" onclick="$('#form_to_submit').submit()">Submit With Onclick!</button>
</form>
Nowadays, not only this looks evil, but it has one (perhaps others) huge pitfall. If one request is made through this process, and the client goes somewhere, and then goes back in his browser history, it'll send the request again.
To fix this last problem, there are many solutions. I think the one I prefer the most is to use real AJAX instead of iframes. Now, in theory, I could change every single form in the source code to make it use AJAX, but I know I won't have 1 straight week of work just for this purpose.
I'm looking for a "quick" way to intercept these requests before they're sent to the iframe, and send them with AJAX instead.
So far, I tried to target <form> tags which have a target="iframe_name" and listen to the submit event to then send the request again with a same method/URL/data.
$('form[target=iframe_name]').on('submit', function (event) {
event.preventDefault(event);
var url = $(this).attr('action'),
datas = $(this).serialize();
$.post(url, datas).done(function (response) {
eval($(response).text());
});
});
But that only works if they're submitted through a real click on a submit button. I'd say 95% of these cases are submitted through onclick tags which will .submit() the forms, and in these cases, the submit event won't trigger it appears.
I'm stuck, any idea ?
Note : I'm tagging jquery only to let you know it's available to be used, even though the question is still relevant with any lib/framework of JS.
You can actually remove the onclick attributes just by doing a general jQuery action on document ready:
<script>
$(document).ready(function() {
var getButton = $('form').find('button');
getButton.prop('onclick',null);
// put listener script here for new form submit (using ajax)...
});
</script>
This piece of code just does a general lookup on the page for all forms, finds the buttons, then removes the onclick attribute. Once you do this the form should not submit anymore with that inline javascript.
I would suggest this be temporary as you incrementally change the forms over time to natively work using the jQuery listener (like the other 5% of forms you have created with no onclick).
Im trying to track when a user hits the submit button on a contact form.
The page's URL doesn't change, its static.
I can't track a differnt URL after submission, the only option would be to track when a user hits the submit button.
Do I need to edit my analytics account?
Where do I add the additional javascript?
UA is installed correctly (analytics.js)
I'm new to GA and javascript so please break it down for me.
Thanks
I can't track a differnt URL after submission, the only option would be to track when a user hits the submit button.
That is a bit of a non sequitur. Even when the Url does not change there is probably some stuff happening - before you send it there is probably some form validation, and there is some action behind the scene to send there form, like e.g an ajax call.
You could attach event tracking to a submit handler:
<form onSubmit="ga('send','event','category','action','label')">
<input type="text" id="text" name="text">
<input type="submit">
</form>
However this would just tell you that somebody hit the submit button, not if they filled in the form correctly or if the form actually has been sent.
Now I enter speculation land, because I do not know how your form actually works - maybe you can show us an url or give more information.
But maybe you have a validation function that is called on the submit action of the form to see if the form is filled in correctly. In that case it would be advisable to do the tracking in the validation function (horribly simplified example, not production code):
<form onSubmit="validate()"><input type="text" id="text" name="text"><input type="submit"></form>
<script>
function validate() {
var test = document.querySelector('#text').value
if(test = "") {
ga('send','event','Form','Submit','Submitted, but not filled in');
return false;
}
ga('send','event','Form','Submit','Submitted with correct values');
return true;
}
</script>
That's a tad better, at least it tracks the difference between correct submissions and invalid submissions.
Even more speculation: If your form is sent without page reloads it uses probably an ajax call, and there is a huge probability that is uses jQuery (I say that because a) it really is probable and b) it's easier to construct an example in jQuery. The same can be achivied with other libraries or in native JS, but the example will produce an error if you do not use jQuery).
jQuery has a thing called "global ajax handlers". "Global" means they are not callbacks for a specific action, they hook into jQuerys ajax "mechanism" whenever a call to an ajax function is made. The following might work if you have only one aja event per page (else you need logic to distinguish the different ajax event e.g, by checking the url they are being send to), and allows you to track if the ajax call has returned successfully, like when your form data has been send to the server and the request return a 2xx status code:
$(document).ajaxSuccess(function() {
ga('send','event','Form','Submit','Yeah, form data sent to the server');
});
However this does not tell you if the data has been processed correctly. For that you need to make the server emit a success message and check the response:
$( document ).ajaxSuccess(function( event, xhr, settings ) {
if ( settings.url == "formprocessor.php" ) {
if(xhr.responseText.indexOf("success") > -1) {
ga('send','event','Form','Response Received','Form data processed ');
} else {
ga('send','event','Form','Response Received','Form data NOT processed ');
}
}
});
The global ajax event handler is attached to the document - you can put that anywhere on your page, it will do nothing unless an ajax event was called.
Again, this is not production code. Do not try to copy and paste.
This was certainly a bit much if you are new to this, but it should at least help you to improve the question and to see what kind of things are possible. If you can share an Url to your form I can possibly improve the answer.
I have a large .aspx page, with multiple server controls. And, there is also a JavaScript file referenced by this .aspx page. I want to have a JavaScript function within this existing .js file, that will get called before any postback that happens to the server.
[note: I have seen another post that mention how to do this in JQuery ( How to capture submit event using jQuery in an ASP.NET application? ), but I would like that to be done through the existing JavaScript file, rather than using a new technology like JQuery]
[Edited] Solution of using OnSubmit handler will not work for me...because it will not get called for postbacks that get triggered by server controls.
You need something like this:
/*
usually there is only one form in asp.net, but if you know you can have
more than one, you can get main form with document.getElementById
*/
var form = document.getElementsByTagName("form")[0];
if (form.addEventListener) {
form.addEventListener('submit', functionThatShouldBeCalledBeforeSubmit, false);
} else if (form.attachEvent) {
form.attachEvent('onsubmit', functionThatShouldBeCalledBeforeSubmit);
}
onsubmit event will rise any time form is submitted. No matter how.
More details about attaching events with JS: https://developer.mozilla.org/en-US/docs/DOM/element.addEventListener
I have a form embedded in a web page. When the user clicks submit the XHR response is either a form with all fields reset (i.e. upon success), or a form with error messages (i.e. upon failure). I use the response to overwrite the existing form.
This works the first time the user submits the form. If they submit a second time however, the problem is that the form is posting a full HTTP request.
In the web page the form is wrapped in a span, #add-container. The button within the form is #add-button.
Per the code below, I am trying to re-bind a function to the click event of the buttom whenever the content in the span changes. It seems that this works the first time (i.e. when the document loads), but not subsequent times (i.e. when the XHR response is loaded into the page).
// Add product and services
$(document).ready(function() {
$("#add-container").change(prepareAddForm());
});
function prepareAddForm() {
var uri = '/product/add/org/4/format/html';
$("#add-button").click(function() {
$("#add-container").load(uri, {language: "php", version: 5});
return false;
});
}
Any ideas? Thanks for your assistance...
Sorry - just sorted it out. Needed to use the .live() method!
I need to track an event in google analytics when someone fills out a form and clicks submit. The resulting page that comes up is a standard dashboard-type page, so in order to track the event on that page I'd have to pass in the event in the url and then read the url and output the google analytics event tracking javascript code based on it. This is a frequently bookmarked page though and page that is reloaded, clicked back to, etc. So I'd really rather not pass tracking events in the URL and screw up the analytics.
Instead, I'd much rather do something like the following jQuery code on the page with the form:
$('#form_id').submit(function() {
_gaq.push('_trackEvent', 'my category', 'my action');
});
The problem I fear with the above is that I'm going to miss some events being tracked because immediately after calling that javascript the browser is going to submit the form and go to another webpage. If the utm.gif tracking image isn't loaded in time, I miss the event :(.
Is my fear justified? How do I ensure I don't miss events being tracked?
Use Google Analytics hitCallback
You can specify a custom callback function on the tracker object.
_gaq.push(['_set', 'hitCallback', function(){}]);
The callback is invoked after the "hit is sent successfully."
If you want to track a click on a submit button and send the form afterwards you can use the following code (uses jQuery) for your event:
var _this = this; // The form input element that was just clicked
_gaq.push(['_set','hitCallback',function() {
$(_this).parents('form').first().submit(); // Submit underlying form
}]);
_gaq.push(['_trackEvent', 'My category', 'My action']);
return !window._gat; // Ensure that the event is bubbled if GA is not loaded
Or as onclickone liner for your <input type="submit"> element:
onclick="var _this=this;_gaq.push(['_set','hitCallback',function(){$(_this).parents('form').first().submit();}]);_gaq.push(['_trackEvent','My category','My action']);return !window._gat;"
What it does it that it tracks the event My category/My action, uses jQuery to find the underlying form element of the submit button just pushed, and then submits the whole form.
See: Google Analytics - Sending Data to Google Analytics - Hit Callback (thanks supervacuo)
UPDATE
If you're using modern analytics.js code with ga() function defined, you can write this as following:
var _this = this;
ga('send', 'event', 'My category', 'My action', {
'hitCallback': function() {
$(_this).parents('form').first().submit();
}
});
return !window.ga;
There are only 2 ways to ensure, 100%, that all form submissions (amongst users who have JS enabled and who don't block GA) is as follows:
You can do an AJAX submit, and then not have to worry about the page changing, and thus have all the time in the world for GA to process AND your new page to load in place of the old one.
You can force the form to open its action in a new window, thus leaving all background processes on the main page working, and preventing the race condition you're worried about.
The reason for this is that Google Analytics does not have a callback function, so you can't ever be certain you're capturing all of the submits, even if you put a 10 second lag.
Alternately, you can just pass a GET value to the submitted page and setup a check on that page for the value. If its set, you can send a trackEvent call.
For those who deal with google analytics universal and doing some trick with hitCallback (f.x. track event after validation but before submit of form) keep in mind that google-analytics.js potentially could be blocked, however ga function will be still defined, so submit will not happen.
ga('send', 'pageview', event, {
'hitCallback': function() {
_this.submit();
}
})
return !window.ga;
Can be fixed with validation that check if ga is loaded
ga('send', 'pageview', event, {
'hitCallback': function() {
_this.submit();
}
})
return !(ga.hasOwnProperty('loaded') && ga.loaded === true)
This question is a few years old now, and it seems that google analytics has provided a way to do this without the hacks given above.
From the google analytics docs:
In addition to command arrays, you can also push function objects onto the _gaq queue. The functions can contain any arbitrary JavaScript and like command arrays, they are executed in the order in which they are pushed onto _gaq.
You can combine this with multiple-command pushing to make aboslute sure that they are added in order (and save a call).
$('input[type="submit"]').click(function(e) {
// Prevent the form being submitted just yet
e.preventDefault();
// Keep a reference to this dom element for the callback
var _this = this;
_gaq.push(
// Queue the tracking event
['_trackEvent', 'Your event', 'Your action'],
// Queue the callback function immediately after.
// This will execute in order.
function() {
// Submit the parent form
$(_this).parents('form').submit();
}
);
});
If you aren't too bothered about 100% accuracy, you could just stick a 1-second delay in.
$('#form_id').submit(function(e) {
var form = this;
e.preventDefault(); // disable the default submit action
_gaq.push('_trackEvent', 'my category', 'my action');
$(':input', this).attr('disabled', true); // disable all elements in the form, to avoid multiple clicks
setTimeout(function() { // after 1 second, submit the form
form.submit();
}, 1000);
});
WHile the hitCallback solution is good, I prefer setting a cookie and triggering the event from the next page. In this way a failure in GA won't stop my site:
// Function to set the event to be tracked:
function setDelayedEvent(category, action, label, value) {
document.cookie='ev='+escape(category)+'!'+escape(action)+'!'+escape(label)+'!'+value
+'; path=/; expires='+new Date(new Date().getTime()+60000).toUTCString();
}
// Code run in every page, in case the previous page left an event to be tracked:
var formErrorCount= formErrorCount || 0;
var ev= document.cookie.match('(?:;\\s*|^)ev=([^!]*)!([^!]*)!([^!]+)!([^!]+)(?:;|\s*$)');
if (ev && ev.length>2) {
_gaq.push(['_trackEvent', unescape(ev[1]), unescape(ev[2]),
unescape(ev[3]), parseInt(ev[4])]);
document.cookie='ev=; path=/; expires='+new Date(new Date().getTime()-1000).toUTCString();
}
This is how you do event callbacks in gtag.js, to ensure Google Analytics data is sent before you change the page URL:
gtag('event', 'view_promotion', { myParameter: myValue, event_callback: function () {
console.log('Done!');
// Now submit form or change location.href
} });
Source: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-hits
Okay since we have moved to Universal analytics, I would like to answer the same using GTM and UA.
GTM:
Track event in google analytics upon clicking form submit is fairly easy using GTM.
Create a UA tag and set the type to event in GTM.
Fill your desired Event Action, Category and Label
Create the trigger of type Form Submission.
Put more conditions to target the button you desire
This is the best, optimal and easy going approach for the OP.
When it's crucial that every submit is tracked, I usually set a cookie on the backend with all required data. Then set up a rule in GTM to fire off a tag based on existence of this 1st party cookie. The tag parses the cookie for required values and does whatever is required with them and remove the cookie.
A more complex example is purchase tracking.
You want to fire off 5 different tags when user performs a purchase. Race conditions and the immediate redirect to some welcome page make it difficult to rely on simple "onSubmit" tracking. So I set a cookie with all purchase-related data and on whatever page the user ends up on GTM will recognize the cookie, fire off an "entry point" tag which will parse the cookie, push all values to dataLayer, remove the cookie and then the tag itself will push events to dataLayer thereby triggering the 5 tags that require the purchase data (which is already in dataLayer).