I have the following Jquery code that listens to a user typing in a captcha and sends an ajax request on each keyup to see if the correct code has been typed:
$('#joinCaptchaTextBox').keyup(function() {
$.get('scripts/ajax/script.php', {
'join_captcha': '1',
'captcha': $('#joinCaptchaTextBox').val()},
function(data) {
var obj = JSON.parse(data);
if(obj.ajaxResponse.status) {
$('#joinCaptchaNotAcceptable').hide();
$('#joinCaptchaAcceptable').show();
}else{
$('#joinCaptchaAcceptable').hide();
$('#joinCaptchaNotAcceptable').show();
}
});
});
The PHP script on the other end just checks the session and replies:
if($siteCaptcha == $_SESSION['secretword']) {
$this->captchaCompare = TRUE;
}else{
$this->captchaCompare = FALSE;
}
This works fine 95% of the time but I'm finding sometimes it reports the captcha typed is incorrect even though its correct. I think this could be because when typed fast many requests are sent to the server and the order or requests coming back isn't the order sent and therefore (as only one will be correct) a prior one is recieved last and incorrect is displayed.
Is there a better way to do this? Is there a way to ensure the last request sent is recieved last? Is there something I'm missing here. I can give more info.
thankyou
Add a timeout so as to not send a request on every keyup when the user types fast:
$('#joinCaptchaTextBox').on('keyup', function() {
clearTimeout( $(this).data('timer') );
$(this).data('timer',
setTimeout(function() {
var data = {
join_captcha: '1',
captcha : $('#joinCaptchaTextBox').val()
};
$.ajax({
url : 'scripts/ajax/script.php',
data: data,
dataType: 'json'
}).done(function(result) {
$('#joinCaptchaNotAcceptable').toggle(!result.ajaxResponse.status);
$('#joinCaptchaAcceptable').toggle(result.ajaxResponse.status);
});
},500)
);
});
Related
Having no luck with the following jQuery code. Supposed to validate form input on submit. Password set correctly. On first submit, err is true. Submit second time (password unchanged), err is correctly set to false.
var err = true;
$( "#signupform" ).submit(function( event ) {
var span_supassword = $('#span_supassword');
var password = $("#supassword").val();
$.ajax({
url: '/apps/ajax/signupvalidate.php',
data: 'action=checkpassword&password=' + password,
dataType: 'json',
type: 'post',
success: function (j) {
if (j.passwordmsg) {
err = true;
span_supassword.html(j.passwordmsg);
}
else { err = false; }
}
});
if (err) { event.preventDefault(); }
});
Any ideas or suggestions?
You call 'async' (not synchronized = call web server and when get answer start 'success' function) query to web server and do not wait for answer!
Just check 'err' variable and at first 'submit' it's as default 'err = true', when you click again submit 'err' is filled with answer from web server and it shows real value.
If you test on local PC web server, it should generate answer in ~0.1 sec and then it call 'success' function!].
Very stupid solution would be:
err = null; // delete value every call
var span_supassword = $('#span_supassword');
... (jquery code) ...
while(err == null)
{// freez web browser until you get answer from server
}
if (err) { event.preventDefault(); }
but it will freez website until it get answer from web server.
Real jQuery solution:
1. Add 'change' event to all 'input' fields that you want to validate.
2. Every 'change' event execute AJAX to validate current field value.
3. Save validation result in variables like 'validationPasswordField = answerFromAjax'
4. in 'submit' event execute something like:
if(!validationPasswordField || !validationUsernameField || !validationAcceptedRegistrationRules)
{
// if any validation failed (is 'false') block submit
e.preventDefault();
}
I have a jQuery validation script that is working perfectly with the except of the event handler. I have simplified this post for troubleshooting purposes.
jQuery
submitHandler: function (form) {
$.ajax({
type: $(form).attr("method"),
url: $(form).attr("action"),
data: $(form).serialize(),
dataType : "json"
})
.done(function (data) {
if (data.resp > 0 ) {
alert(data.message);
}
});
return false; // required to block normal submit since you used ajax
},
// rest of the validation below, truncated for clarity
The submitHandler successfully posts to my PHP script that adds a user to a database and then echoes back a json_encode() result.
PHP
<?php
// All processing code above this line has been truncated for brevity
if($rows == "1"){
$resp = array("resp"=>1, "message"=>"Account created successfully. Waiting for user activation.");
}else{
$resp = array("resp"=>2, "message"=>"User account already exists.");
}
echo json_encode($resp);
?>
As you can see the idea is simple. Alert the user with the proper response message. When I run my script the user account is added successfully to the database but no alert is displayed to the user. The Console in Chrome shows no errors, what am I missing?
The data variable in the done() is a string. You have to transform it to an object like this
var response = $.parseJSON(data);
in order to access the attributes
I am sorry I missed dataType : "json" in your code in my previous answer.
Any way I tried your code and it is working. The alert shows the message. I think you have an error somewhere else. I think it has some thing to do with the array you are encoding to json(PHP part). The response you get is not complete. Try to debug your PHP and test the page separately from AJAX and see what is the result
After some tinkering I was able to get things working the way I wanted. Here's the updated code.
jQuery
.done(function (data) {
$("#user_add_dialog").dialog({
autoOpen: false,
modal: true,
close: function (event, ui) {
},
title: "Add User",
resizable: false,
width: 500,
height: "auto"
});
$("#user_add_dialog").html(data.message);
$("#user_add_dialog").dialog("open");
});
return false; // required to block normal submit since you used ajax
PHP
<?php
// All processing code above this line has been truncated for brevity
if($rows == "1"){
$resp = array("message"=>"Account created successfully. Waiting for user activation.");
}else{
$resp = array("message"=>"User account already exists.");
}
echo json_encode($resp);
?>
At this moment I am using laravel. In this context I am having a form which is successfully submitted by using ajax to a controller. and that controller make it to the database. But the problem is as the ajax is doing its job the whole page remain unmoved / unchanged after the submission even the database is updated.
Now what I want
I want to give feedback to the user that your post is successfully submitted there. or what I want to do in further, I want to refresh the section in which the post is collected from the database as this post can be retrieved from there. But by using ajax only.
So there is no need to collect the whole page or refresh.
here is my form structure
`
{{ Form::open(array('route' => array('questions.store'), 'class' => 'form-horizontal' )) }}
blah blah blaaa .......
<script type="text/javascript">
$(".form-horizontal").submit(function(e){
$(this).unbind("submit")
$("#ask").attr("disabled", "disabled")
var that = $(this),
url = that.attr('action'),
type = that.attr('method'),
data = {};
that.find('[name]').each(function(index, value){
var that = $(this),
name = that.attr('name'),
value = that.val();
data[name] = value;
});
$.ajax({
url: url,
type: type,
data: data,
success: function(response){
console.log(response);
}
});
return false;
});
</script>
{{ Form::close() }}
`
As it is very much visible that the post is updated through a route & controller I want to have another dive and a success message at this script to be displayed after the success of posting. I am looking for some professional structure using what there is minimal need to have interaction with the server side and give user a better page viewing experience.
Thanks a lot for helping me in this research.
I am not sure if I understand you well, but if you want to notify the user about the result of an ajax-called db update you need to have
a route for the ajax save db call - it should point to a method that does the db update.
the db update method should return some value indicating the success/failure of update (for example OK or FAIL)
the only result of calling the method will be just plain text page with OK or FAIL as body
fetch the result by ajax and inform user accordingly (after form submit button)
check out the below code for ajax call itself (inside the form submit handler) to see what I mean
var db_ajax_handler = "URL_TO_YOUR_SITE_AND_ROUTE";
var $id = 1; //some id of post to update
var $content = "blablabla" //the cotent to update
$.ajax({
cache: false,
timeout: 10000,
type: 'POST',
tryCount : 0,
retryLimit : 3,
url: db_ajax_handler,
data: { content: $content, id: $id }, /* best to give a CSRF security token here as well */
beforeSend:function(){
},
success:function(data, textStatus, xhr){
if(data == "OK")
{
$('div.result').html('The new Question has been created');
}
else
{
$('div.result').html('Sorry, the new Question has not been created');
}
},
error : function(xhr, textStatus, errorThrown ) {
if (textStatus == 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) {
//try again
$.ajax(this);
return;
}
return;
}
if (xhr.status == 500) {
alert("Error 500: "+xhr.status+": "+xhr.statusText);
} else {
alert("Error: "+xhr.status+": "+xhr.statusText);
}
},
complete : function(xhr, textStatus) {
}
});
EDIT: as per comment, in step 2 (the method that is called with AJAX) replace
if($s)
{
return Redirect::route('questions.index') ->with('flash', 'The new Question has been created');
}
with
return ($s) ? Response::make("OK") : Response::make("FAIL");
EDIT 2:
To pass validation errors to the ajax-returned-results, you cannot use
return Response::make("FAIL")
->withInput()
->withErrors($s->errors());
as in your GIST. Instead you have to modify the suggested solution to work on JSON response instead of a plain text OK/FAIL. That way you can include the errors in the response and still benefit from the AJAX call (not having to refresh the page to retrieve the $errors from session). Check this post on the Laravel Forum for a working solution - you will get the idea and be able to fix your code.
I've been on a problem for hours without finding any issue...
I have a registration form for users to create accounts. When the submit button is pressed a validateForm function is called.
In this function I do some javascript tests that work, but then I need to verify that the username is available. For this I created an external PHP file and call it using $.ajax.
Here is part of the code :
function validateRegistration(){
// Some tests....
// Check if username is already used
// Call external php file to get information about the username
$.ajax({
url: 'AjaxFunctions/getUsernameAjax.php',
data: "username=" + $("#username").val(),
success: function(data){
// Username already in use
if(data == "ko"){
// Stop validateForm()
}
// Username not used yet
else{
// Continue tests
}
}
});
// Other tests
}
My question is how can I make validateForm() return false from inside the $.ajax ?
Could I for instance declare a js variable before the Ajax part and set it with Ajax ?
I guess the answer is obvious but I'm absolutely new to Ajax and I can't get it...
Thanks a lot for your help!
To achieve this you can either do a synchronous ajax call like described in this answer, but that's something which is incredibly dangerous for the performance of your website.
Alternatively - and this is the right way - you should have an external variable whether the username is available, as soon as the user inputs something you do the request and if it's valid you change the variable otherwise you show an warning message. Next in your validateRegistration() function you only check the external variable (+ possible some form of callback, depending on where you call it from). The advantage being that the user can still continue doing things (like filling out the rest of the form) whilst the request is pending.
You could make a synchronous ajax call, instead of an asynchronous, as you're doing now. This means that the Ajax call will complete before the next lines of code are executed.
To do so in jQuery, just add async: false to your request object:
var someVariable;
$.ajax({
url: 'AjaxFunctions/getUsernameAjax.php',
data: "username=" + $("#username").val(),
success: function(data){
// Username already in use
someVariable = "something";
if(data == "ko"){
// Stop validateForm()
}
// Username not used yet
else{
// Continue tests
}
},
async: false
});
alert(someVariable); // should alert 'something', as long as the ajax request was successful
In the php, if you print out JSON like:
echo json_encode(array("ko"=>"good"));
shows up as:
{
"ko":"good"
}
then in the function it would be
if(data.ko == "good"){
//do stuff
}
This is how I normally do it. You can get the variable by using the name you used in the JSON so you can have other things if you need.
If the goal is to check a username availability, how about checking it as or just after the username is typed in. For example you could either bind it to the keyUp event for keystrokes or the blur event for when you leave the text box.
This would mean that by the time the user gets to the submit button, that part of the form would already be validated.
The traditional solution here is to pass a callback function to validateRegistration which expects a boolean value. Have the Ajax function call the callback function when it completes.
The onsubmit handler expects a return value immeidately, so performing an asynchronous test within your submit event handler is a fairly unituitive way to do things. You should instead perform the test as soon as possible (e.g. as soon as the user enters a username) and then store the result of username validation in a global variable, which is later checked at submit time.
// global variable indicating that all is clear for submission
shouldSubmit = false;
// run this when the user enters an name, e.g. onkeyup or onchange on the username field
function validateRegistration(callback) {
shouldSubmit = false;
// number of ajax calls should be minimized
// so do all other checks first
if(username.length < 3) {
callback(false);
} else if(username.indexOf("spam") != -1) {
callback(false)
} else {
$.ajax({
....
success: function() {
if(data == "ko") {
callback(false);
} else {
callback(true);
}
}
});
}
}
Now call validateRegistration with a function argument:
validateRegistration(function(result) {
alert("username valid? " + result);
if(result) {
$("#username").addClass("valid-checkmark");
} else {
$("#username").addClass("invalid-xmark");
}
shouldSubmit = result;
});
Now use the global variable shouldSubmit in your form's submit event handler to optionally block form submission.
NOTE:
I gave up on trying to do the processing in one go, and just let it return after every x number of sends.
Two paths,
/sms?action=send
/sms?action=status
Let's say that the send path starts sending 10,000 sms messages via REST api calls.
I make a call to that page via ajax.
Then every few seconds, I make a call to /sms?action=status to see how the progress is going, and to update a progress bar.
The status path returns false if no messages are being sent.
What ends up happening is that the ajax call to the SEND path gets the ajax success: function called almost instantly, even though I know the script is taking 1+ minute to complete execution.
My progress bar never gets shown because the status ajax call (which is in a set interval with a few second delay) never seems to actually get called until the send call completes.
I'm trying to put the relevant code in here, but it may not be as clear as it should be without all the context.
<script type="text/javascript">
var smsInterval = 0;
var smsSending = false;
$(document).ready(function() {
var charCount = 0;
var smsText = "";
var smsTotal = <?php echo $options["smsTotal"]; ?>;
<?php if($options["sending"]): ?>
smsStatus();
smsSending = true;
smsInterval = setInterval("smsStatus()", 5000);
<?php endif; ?>
$("span#smsadmin_charcount").html(charCount.toString());
//send button
$("div#smssend").click(function() {
if(smsSending == true) {
return false;
}
smsStatus();
var dataString = $("#smsadmin_form").serialize();
smsSending = true;
$("div#smssend").html("Sending...");
$.ajax({
type: "POST",
url: "<?php echo $base_url; ?>/admin/sms",
data : dataString,
success: function(data) {
},
error: function(request, error) {
$("div.notice.sms").html("ERROR "+error+ "REQUEST "+request);
}
});
});
});
function smsStatus() {
var dataString = "smsaction=status&ajax=true";
$.ajax({
type: "POST",
url: "<?php echo $base_url; ?>/admin/sms",
data : dataString,
success: function(data) {
//data being false here indicates the process finished
if(data == false) {
clearInterval(smsInterval);
var basewidth = $("div.sms_progress_bg").width();
$("div.sms_progress_bar").width(parseInt(basewidth));
$("div.sms_progress_notice").html(parseInt(100) + "% Complete");
smsSending = false;
$("div#smssend").html("Send To <?php echo $options["smsTotal"]; ?> Recipients");
} else {
var pcomplete = parseFloat(data);
$("div.sms_progress_bg").show();
var basewidth = $("div.sms_progress_bg").width();
$("div.sms_progress_bar").width(parseInt(basewidth * pcomplete));
$("div.sms_progress_notice").html(parseInt(pcomplete * 100) + "% Complete");
}
},
error: function(request, error) {
$("div.notice.sms").html("ERROR "+error+ "REQUEST "+request);
}
});
}
I might be missing the point, but inside the $("div#smssend").click you got this line:
smsStatus();
shouldn't it be:
smsInterval = setInterval("smsStatus()", 5000);
and INSIDE the success: function(data) for /admin/sms ?
If the send part is sending out 10k messages, and the status returns true if currently sending a message, and false if in between sending, then you have a design issue.
For example, what is status supposed to be showing?
If status is to show how many of a certain block have been sent, then what you can do is to submit the message to be sent (or addresses), and get back some id for that block.
Then, when you ask for a status, pass the id, and your server can determine how many of that group has been sent, and return back the number that were successful, and unsuccessful, and how many are still pending. If you want to get fancy, you can also give an indication how much longer it may be before finishing, based on how many other requests are also pending.
But, how you approach this really depends on what you expect when you ask for the status.