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.
Related
I have a registration form for my website that requires a user to fill in ~6 fields, with their email as their username on the system. When a user registers, I want to first check if they are not already a registered user in our system, and if they are, redirect them to the login page. If they are not registered, registration should proceed to the registration page.
I've been trying to do this with the following ajax code, but it doesn't work - if the user is already registered, it still proceeds to the registration page:
function Chkreg()
{
var uemail = document.registration.email;
var not_reg;
$.ajax({
async: false,
type: "POST",
url: "chkreg.php",
data : "email="+uemail.value,
dataType: "json",
success: function (data) {
var success = data['success'];
if(success == false){
var error = data['message'];
alert(error);
window.location.href="login.php";
not_reg = false;
return false;
}
if(success == true) {
not_reg = true;
return true;
}
}
});//end ajax
return not_reg:;
}//end function
The form itself is defined as follows:
`<form name='registration' method="POST" action="registration/register.php" onsubmit="return Chkreg();">`
so, a false return from the Chkreg function should not post to register.php, but Chkreg() seems to always return true.
Any ideas how to fix it, or an alternate way to do this?
Because you're doing the ajax call with async:false, you don't need the return true or return false inside of it. That could be where things are going wrong, since you are returning from the anonymous function in the ajax call, not Chkreg(). Just returning not_reg outside of the ajax call will work.
That said, I would declare not_reg = false when you initialize the var. That way it's false until proven true. Or vice-y-versa -- I can't tell because of the negation in the variable name.
Also, inside of your (success == false) if-block, you are executing
window.location.href = "login.php";
which immediately redirects the user to login.php. You may want to alter the flow entirely and change the inline js for the form's onsubmit event
onsubmit="Chkreg(); return false;"
Then, inside Chkreg(), you could submit the form with javascript if they are not a registered user already.
Also, === and !== are preferred over == and != (especially when establishing if a variable is true or false, in case your values can be interpreted as truthy).
Lastly, Developer Tools are your friend (or Firebug). What response is the server giving when chkreg.php is being requested?
Check what the actual response is with firebug (or whatever your browsers dev kit)....I would be what you want is
if (success == "false") {
I've never done this before, and I haven't found much help on Google or StackOverflow yet.
Here's what I have: A password input:
<input type="text" placeholder="password" name="pass" id="password" />
and some jQuery to check the password:
<script>
$('form').submit(function(){
input = $('#password').val();
var finish = $.post("pass.php", { request: "opensesame" }, function(data) {
return (input==data) ? true : false;
});
if(finish){
alert('sent');
}else{
alert('not sent');
}
return false;
});
</script>
And a password-dispensing php page (pass.php):
<?php
if(isset($_POST['request'])&&$_POST['request']=="opensesame"){
echo 'graphics';
}
?>
Now, I can get it to alert 'graphics', but I can't get it to match the data with the input value to check if it's the right password or not.
What am I doing wrong, and what are the potential dangers to authenticating a password in this way?
The "A" in "AJAX" stands for asynchronous.
The code after you call $post will execute before the contents of the $post function. The value of finish will always be a jqXHR object, the result of (input==data) ? true : false will be ignored.
More clearly:
var finish = $.post("pass.php", { request: "opensesame" }, function(data) {
// THIS EXECUTES SECOND, and the return value is discarded
return (input==data) ? true : false;
});
// THIS EXECUTES FIRST, with finish set to a jqXHR object
if(finish){
...
You need to rethink your methods of password checking, or use synchronous postbacks by adding the following before your $.post calls:
$.ajaxSetup({async:false});
Or by using $.ajax and passing async: false:
jQuery.ajax({
type: 'POST',
url: "pass.php",
data: { request: "opensesame" },
success: function(result) { ... },
async: false
});
The first thing to do would be to clean up the code, it's too obscure, I'm afraid.
I'd write it as follows:
<script>
$('form').submit(function(event){
event.preventDefault(); // stop the form from submitting
var passwd = $('#password').val();
var finish = $.post("pass.php", { request: passwd }, function(data) {
if(data){
alert('Success!');
}else{
alert('Failure :(');
}
});
});
</script>
Things to note here:
AJAX POST is asynchronous, you can't check for a variable right after changing it in the callback, you need to process stuff inside the callback.
You must verify the password on the server, not in javascript!!
Adding to the previous bullet, don't write your password inside the javascript!
And on the server:
<?php
if(isset($_POST['request']) && $_POST['request']=="opensesame"){
echo 'true';
}else{
echo 'false';
}
?>
Things to note here:
You used isset() to check for the existence of the variable, good call. Keep doing it.
jQuery POST expects a javascript value from the server (unless you tell it otherwise).
This is why my code prints either 'true' or 'false', this translates to a boolean value in javascript.
I would advise returning an object with error details, such as the one below:
<?php
$result = array('success'=>false, 'reason'=>'Unknown error.');
if(isset($_POST['request'])){
if(trim($_POST['request'])!=''){
if($_POST['request']=='opensesame'){
$result['success'] = true;
$result['reason'] = 'Welcome home!';
}else $result['reason'] = 'Password is wrong';
}else $result['reason'] = 'Password must not be empty';
}else $result['reason'] = 'Expected parameter "request"';
echo json_encode($result);
?>
You have to serialize your input fields to all the data to your script:
$.post("pass.php", { request: $('form').serialize() }, function(data) {
// ...
As long as you are on your own server I don't see much potential dangers, as it sends a POST-request which a normal form would do anyway.
Its quite unsafe to send data like this, anyone can intercept and read the data which you send by ajax and the value returned by ajax using firebug or other such tools. So you should serialize or sanitize the fields and also encrypt the data before sending them.
& the code to alert after checking finish will be executed before the response comes from ajax (note that it is asynchronous) thus you would get an object stored in the finish variable.
Im currently new to PHP and JQuery after having using ASP.Net and C Sharp for the 2 years. I have this major problem in which i require some assistance in.
I have a HTML <input type="submit" id="btnWL" value="Add to Wishlist"> button. Basically when this button is pressed a table called 'wishlist' in the database is checked to see if the current product is already in a wishlist. If no the button will trigger a database save else it will return a JQuery alert pop up error message.
I having difficulty in passing 2 PHP variables: $_SESSION["username"] and $_GET["ProductId"] into this JQuery method:
<script type="text/javascript">
$(document).ready(function() {
$('#btnWL').live('click', function() {
$.post("addToWishlist.php");
});
});
</script>
As you can see this JQuery method must pass those values to an external PHP File which checks for an already exsisting record in the 'wishist' table with those details.
<?php
$WishlistDAL = new WishlistDAL();
$result = $WishlistDAL->get_ProductInWishlistById($_GET["ProductId"]);
if (isset($_POST["isPostBack"])) {
if (isset($_SESSION["username"])) {
if (isset($_GET["btnWL"])) {
//Check if ProductId is in Cart
if (mssql_num_rows($result)>0)
{
//Return an error
//Sumhow this has to trigger an alert box in the above JQuery method
}
else
{
//Write in Wishlist Table
$WishlistDAL->insert_ProductInWishlist($_GET["ProductId"], $_SESSION["username"]);
}
}
}
else
{
//Return Error
}
}
?>
Another problem I have is then displaying an alert box using the same JQuery method for any errors that where generated in the php file.
Any Ideas how I can implement this logic? Thanks in advance.
Your "$.post()" call isn't passing any parameters, and has no callback for interpreting the results:
$.post('addToWishlist.php', { username: something, password: something }, function (response) {
});
The "something" and "something" would probably come from your input fields, so:
$.post('addToWishlist.php', { username: $('#username').val(), password: $('#password').val() }, function (response) {
});
Now the callback function would interpret the response from the server:
$.post('addToWishlist.php', { username: $('#username').val(), password: $('#password').val() }, function (response) {
if (response === "FAIL") {
alert("fail");
}
else {
// ... whatever ...
}
});
Exactly what that does depends on your server code; that "FAIL" response is something I just made up as an example of course.
jQuery accepts an callback:
$(document).ready(function() {
$('#btnWL').live('click', function() {
$.post("addToWishlist.php", {'isPostBack':1}, function(res){
if (res.match(/err/i)){
alert(res);
}
});
});
});
Then, in the php, just (echo('Error adding record')) for this jquery to see there's an error string in the response and pop up the error message.
Other methods would be to use json, or http status codes and $.ajaxError(function(){ alert('error adding'); });.
from what i can tell so far is you'll only need to pass in the product id in and you can do this by appending your $.post call with the value; this will pass to your php script as a query string variable. i'm not sure which php script you posted, but if you're sending your data with jquery, it's using post and not get, so you may need to make an adjustment there and the session data should be available regardless, since it's the same session.
again this is without seeing all the code and since some of it isn't labeled, it's hard to determine. another thing, i like to use $.ajax for most actions like this, you have a lot more room to define and structure, as well as create one generic ajax function to call the methods and post data, as well as make a response callback. here's the documentation for you to look into $.ajax
i hope this helps.
OK, I'm getting the results of a PHP form from JSON to do a login validation. I want to check to see if their account is activated, which I do just fine. If it's not I show a jQuery error but I want the ability to let them resend the activation email. I can pass the username password to the function displaying the error with JSON, but how do I then pass that data to a new function to process the new email? Here is what I have so far:
// LOGIN Validation
$(function(){
$("#jq_login").submit(function(e){
e.preventDefault();
$.post("widgets/login_process.php", $("#jq_login").serialize(),
function(data){
if(data.all_check == 'invalid'){
$('div.message_error').hide();
$('div.message_success').hide();
$('div.message_error').fadeIn();
$('div.message_error').html(
"<div>UserId and/or password incorrect. Try again.</div>"
);
} elseif(data.user_check == 'invalid'){
$('div.message_error').hide();
$('div.message_success').hide();
$('div.message_error').fadeIn();
$('div.message_error').html(
"<div>UserId and/or password incorrect. Try again.</div>"
);
} elseif (data.activated_check == 'invalid'){
$('div.message_error').hide();
$('div.message_success').hide();
$('div.message_error').fadeIn();
$('div.message_error').html(
"<div>Your account has not been activated. Please check your " +
"email and follow the link to activate your account. Or click " +
"<a href='#' id='resend'>here</a> to re-send the link.</div>"
);
} else {
$('div.message_error').hide();
$('div.message_success').fadeIn();
$('div.message_success').html(
"<div'>You are now logged in. Thank you </div>"
);
window.location.replace("producer.php");
return false;
}
}, "json");
});
});
$(function(){
$("#resend").live('click', function(event){
event.preventDefault();
alert(data.username);
var data = 'username=' + data.username + 'password=' + data.password;
$.ajax
});
});
I'm new so I don't understand all the ins and outs of passing data back and forth.
thank you.
craig
With Ajax there's not really "passing data back and forth," but rather just passing callbacks. That's what you're doing when you put function() { ... } as a function parameter--you're creating a callback.
I think the best course of action is to refactor this into several stand-alone functions. A good best practice is to make each function do one thing only, rather than defining functions within functions within functions.
Once refactored, it becomes more clear how we can "reuse" the username and password for the resend-activation link.
(function() { // to keep these functions out of the global scope(†)
// this will be called when the login form is submitted
function handleLogin(evt) {
evt.preventDefault();
// same as your code except that instead of creating a function here
// we instead pass `handleLoginResponse`, which is a function we'll
// define later
$.post( 'widgets/login_process.php',
$(this).serialize(), // <-- In events, `this` refers to the element that
handleLoginResponse, // fired the event--in this case the form, so we
'json' // don't need its id, we can just give `this`
); // to jQuery.
}
// This is the function we gave to $.post() above, and it'll be called when
// the response is received.
function handleLoginResponse(data) {
// Here we decide what message to show based on the response, just like
// in your code, but we call a function (showError or showSuccess) to
// avoid repeating ourselves.
if(data.all_check == 'invalid') {
showError("UserId and/or password incorrect. Try again.");
} else if(data.user_check == 'invalid') {
showError("UserId and/or password incorrect. Try again.");
} else if(data.activated_check == 'invalid') {
showError("Your account has not been activated. Please check your " +
"email and follow the link to activate your account. Or " +
"click <a href='#' id='resend'>here</a> to re-send the link."
);
} else {
showSuccess("You are now logged in. Thank you.");
redirectToLoggedInPage();
}
}
// the function that shows error messages
function showError(message) {
$('.message_success').hide();
$('.message_error').hide(). // jQuery chaining keeps things tidy
html('<div>' + message + '</div>').
fadeIn();
}
// the function that shows success messages
function showSuccess(message) {
$('div.message_error').hide();
$('div.message_success').fadeIn().
.html('<div>' + message '</div>');
}
// this method is called when the "resend" link is clicked
function handleResendClicked(evt) {
evt.preventDefault();
// send another Ajax request to the script that handles resending, using
// the form values as parameters
$.get( './resend_activation.php',
$('#jq_login').serialize(),
handleResendResponse // again we've defined this function elsewhere
);
}
// called when the Ajax request above gets a response
function handleResendResponse(data) {
// of course you can do whatever you want with `data` here
alert('resend request responded with: ' + data);
}
// called from handleLoginResponse when the login is successful
function redirectToLoggedInPage() {
window.location = './producer.php';
}
// finally, our document.ready call
$(function() {
// pass the names of the functions defined above to the jQuery
// event handlers
$("#jq_login").submit(handleLogin);
$("#resend").live('click', handleResendClicked);
});
}());
Of course, you won't always code like this--sometimes it really is best to just define an anonymous function() { ... } on the spot--but when things are getting nested three-levels deep this is a good way to untangle things and tends to make the way forward more clear.
(†) Anonymous closures for limiting scope
Could the server simply append the confirmation link with the returned json?
$('div.message_error').html(
"<div>Your account has not been activated. Please check your " +
"email and follow the link to activate your account. Or click " +
"<a href='" + data.activation_url + "' id='resend'>here</a> to re-send the link.</div>"
);
Im performing an ajax query to check the name of a car in a mysql database, if a car is found it will return "Car name unavailable", otherwise "Car name available". This text is put into a div with an id of "checkname".
All this runs fine, but when I try to hide the add button if the car name is unavailable it fails to do so and I dont know why :/
function check_name(){
$.ajax({
type: "POST",
url: "http://localhost/Framework/library/php_files/check_car_name.php",
data: "carName=" + document.getElementById("carName").value,
success: function(html){
$("#checkname").html(html);
}
});
var currentHtml = $("#checkname").html();
var compareString = "Car name unavailable";
if (currentHtml==compareString) {
$("#submit").hide();
} else {
$("#submit").show();
}
}
Any code that relies on the response from the AJAX request, must be called inside a callback to the request.
function check_name() {
$.ajax({
type: "POST",
url: "http://localhost/Framework/library/php_files/check_car_name.php",
data: "carName=" + document.getElementById("carName").value,
success: function (html) {
$("#checkname").html(html);
// I placed your code here instead.
// Of course you wouldn't need to set and then get the HTML,
// since you could just do a direct comparison.
var currentHtml = $("#checkname").html();
var compareString = "Car name unavailable";
if (currentHtml == compareString) {
$("#submit").hide();
} else {
$("#submit").show();
}
}
});
}
The reason is that by default, an AJAX request is asynchronous, which means that the code that comes after the request will execute immediately instead of waiting for the response to return.
Another possible issue when comparing HTML to keep in mind is white space. If you're doing a string comparison, it must be exactly the same, so if there's whitespace, you'll need to trim it first. You can use jQuery.trim()(docs) to do this.
You have to put the code inside of you AJAX requests success callback, otherwise it will be called before the AJAX call has completed. Putting it inside the success callback means that the code containing the IF statement will only run after the AJAX call has completed. Try:
function check_name(){
$.ajax({
type: "POST",
url: "http://localhost/Framework/library/php_files/check_car_name.php",
data: "carName=" + document.getElementById("carName").value,
success: function(html){
$("#checkname").html(html);
var currentHtml = $("#checkname").html();
var compareString = "Car name unavailable";
if (currentHtml==compareString) {
$("#submit").hide();
} else {
$("#submit").show();
}
}
});
}
You could probably solve the problem doing what patrick dw suggested (it's likely that the ajax call has not been completed yet (i.e. div content wasn't updated) and the check returns false), but since string comparison can really bring to many errors (like string not matching because of newlines, trailing spaces, case sensitiveness, etc...) I would suggest you use another comparison method.
For example you could add a class using .addClass() if the car is found, and then checking if that div has the "found" class using .hasClass()
I use .post(). The third argument of post() is the returned data from the file where the data was posted.
I pass to validate.php the inputed email address, validate.php checks it and if it is valid, it returns 1.
$('a.post').click(function() {
$.post('validate.php',{email : $("#email-field").val()},
function(data){
if(data==1)
{
//do something if the email is valid
} else {
//do other thing
});
});
Hope this helps.