Strange issue with form onsubmit and javascript xmlhttprequest - javascript

I have a strange issue with my code I can't seem to figure out. I'm relatively new to js and utilizing http requests to retrieve json data however I've been able to come up with code that works, for the most part.
Essentially the workflow is as follows: I have a user enter some form field values and select the submit button. Onsubmit the the apiCall() function is called which then calling the createXMLHttpRequestObject() and constructApiURL(searchtype) functions creates, populates, and sends the xmlHttpRequest Object via the proxy to the search api url. Once the result is returned the handleResults() function is called which then parses and displays the results in the apropriate div container using the handleResultsContainer() function.
Everything works when I step through the code via firebug. The object is created, sent via the proxy to the search api, the results are returned and displayed but once the focus returns to the function onsubmit(event) {callApi();} and the contents then clear!?! I don't know if the page is reloaded or something else is going on.
Now if I change the initial trigger from a form submit to a button onclick it works without issues. The user selects the button, the search results are retrieved and displayed until the user selects the button again at which point the results are cleared and the new results are displayed. The problem is that I have to hard code the parameters I would normally be getting from the form.
Has anyone experienced this or sees something with how the code is being read by the browser that could cause this? My Pseudo code is below.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function createXMLHttpRequestObject() {
-- code to create the XMLHttpRequestObject based on browser type --
}
function constructApiURL(searchtype) {
-- code to create the api url using the form values & proxy url --
}
function handleResultsContainer () {
-- code to create/remove search results display div
}
function handleResults(jsndata) {
-- code to parse and display results here --
}
function callApi() {
-- code to create XMLHttpRequestObject, populate it, and send it --
}
</script>
</head>
<body>
<form id="basicform" name="mashsearch" onsubmit="callApi()">
-- Code for user input fields which are then used by constructApiURL --
<input type="submit" id="searchbtn" value="Search!"/>
</form>
//Div displaying a Search Results Loading… message which is hidden/displayed//
<div id='loadingDiv' style="display:none">Search Results Loading...</div>
//Div used to display the search results
<div id='json'></div>
</body>
</html>

Change your onsubmit to :
onsubmit="callApi();return false;"
Alternatively you could add return false to the bottom of your callApi() method and change your onsubmit to be onsubmit="return callApi()"
If you do not the page will submit and reload as its normal behaviour would.

Related

Invisible re-captcha fully from javascript without form submission

I am trying to use an invisible re-captcha v2 on a form that is submitted through JS. Every example I see online shows a regular plain HTML submitted form with a specified action and method, but I am using preventDefault() on my form to submit it with ajax. It seems like such a simple thing but I've been searching for hours and can't find a single person online who has ever done this.
HMTL:
<form id="form-login">
<!-- ...form fields... -->
<div
class="g-recaptcha"
data-sitekey="<site_key>"
data-size="invisible"
></div>
<button class="uk-button uk-button-primary" type="submit">Submit</button>
</form>
JS:
$('#form-login').submit(function(event) {
event.preventDefault();
console.log(grecaptcha.getResponse()); // <-- always comes back empty
});
I can see that the captcha is initializing because I can see the icon in the bottom right.
I've seen grecaptcha.execute() but it doesn't seem to do anything for me.
There are no errors in the console.
Recently I had a problem like you, making captcha invisible created a lot of issues for me e.g. https://github.com/google/recaptcha/issues/269 which is still an opened issue on GitHub.
I solved it with dynamically genarated captcha on each time form is submitted. Here is a bit of code I used. (commented code is a call to backend to verify response with Google API).
https://gist.github.com/ANTOSzbk/75ed7003e914162550f61399122a3bd4
Then you just use my function like this:
$('#form-login').submit(async function(event) {
event.preventDefault();
const response = await captchaVerification();
if (response) { } // proper submit code execution
else { } // on invalid captcha response
});

Switch from iframe "AJAX" to proper AJAX

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).

How to setup event tracking on Google Analytics on form submission?

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.

How to do "HTML FORM action=location.replace('nextpage.html')"?

The title is actually a failed attempt to achieve my goal. Specifically, I want to
1. Go to a page from main.html (say, to page1.html).
2. Collect data in a form on page1.
3. On Submit, go to page2.html (which saves data to database using PHP and announces result).
4. Click on "Ok" and go back to main menu page.
Seems reasonable, right?
Step 4 above is my problem.
Things I've tried:
1. Invoke history.back on Ok click in page2.
This goes to page1 not main
2. Invoke javascript location.href=main.html on "Ok" in page2
This works and goes to main but clicking on Back button in main brings user back to page1. (not good)
3. Many variations of using javascript history.replace() in action= and onSubmit() of page1.
This works works and but inputs from form are not passed in query string to page2)
4. Clear history.
This appears to be impossible because of security concerns.
5. Programmatically composing the query string for history.replace (from form inputs) on page1.
This works but is very laborious, error-prone and horribly inelegant
Any suggestions will be greatly appreciated.
========= MY SOLUTION 4/8/16 ==============
I'm posting my final solution below for anybody that's interested.
In page1.html:
<script type="text/javascript">
function addarg(q,addend)
{
qnew = q + addend;
return( qnew );
}
function Next()
{
// GET INPUT VALUES FROM FORM
frm = document.forms["MainForm"];
first = frm.first.value;
last = frm.last.value;
phone = frm.phone.value;
// COMPOSE QUERY
query = "processForm.php";
query = addarg( query, '?first='+first );
query = addarg( query, '&last='+last );
query = addarg( query, '&phone='+phone );
location.replace( query ); // chain to processing page
}
</script>
<form action="javascript:Next()" name="MainForm" method=GET>
...
</form>
When history.back() is issued from processForm.php, it returns to Main Menu as desired.
It seems the easier way to achieve this is to place a simple <a href=main.html>Ok</a> on your page2.html.
Then associate a flag (maybe a cookie) on this main.html which "instructs" page1.html to clear its form elements if it is not called by main.html, but from a "back" button (by refreshing meta, for example, or by loading page1.html#randomnum, where randomnum is a value you find real time to force your browser understand this is not the "old" page1.html but a "new" page1.html, helping browser not to get this from cache but from web).
The principle is: if page1.html is called by "back", it have to be a "clear" page1.html, not showing any data input user eventually entered.

javascript history.back losses the search result

Page A:
$(document).ready(function () {
bindData();
});
function bindData() {
$('#searchbtn').bind('click', function () { SearchResult(); });
}
function SearchResult() {
ajax call...
}
Page A HTML:
<input type="button" id="searchbtn" />
Page B Details---> this page comes after selecting a specific search result from page A search list
Back<br />
Now when I go back to the Page A I can see my search criteria's as they were selected but the result Div is gone. What I am trying to do is I want the search list to stay when the Page comes back.
I think what I can do here is some how call the searchbtn click event again when the page comes back so the list will come-up again. Can anyone tell me how to fire the searchbtn click event only when the page comes back from Page B. or point me in the right way of doing this..
Thanks
The Browser Back button has long been problematic with AJAX. There are scripts, workarounds, and techniques out there (depending on the framework that you want to use).
Since it appears that you are using jQuery (based on your posted JavaScript syntax), here is a link to another Stackoverflow post regarding back button jQuery plugins.
history.back() will return you to the last URL visited, meaning that any ajax calls made during the user's visit will not be automatically repeated. Your browser may automatically restore your form selections, but the SearchResults() function is only called by a click event, not a selection event.
You can bind URLs to ajax states using a framework like sammy.js. That way, history.back() would take you to a URL associated with SearchResults().
function bindData() {
var chkinput1 = $("input:checkbox[name=x]:checked").length;
var chkinput2 = $("input:checkbox[name=y]:checked").length;
if (chkinput1 > 0 && chkinput2 > 0) {
SearchResult();
}
$('#searchbtn').bind('click', function () { SearchResult(); });
}
I know this is the worst way to achieve this result but I think instead of using any other plugins to add complexity we will go with this for now. If anyone else is looking for the same question let me tell you again this is not the best practice as on returning back to the history we are calling the search result again depending upon the cached input selection of checkboxes and generating the whole ajax call again to display the list. On the first request I am caching the list and setting sliding expiration so its not taking anytime to comeback and so everyone lives happily.

Categories