0

I have a simple login form using javascript, ajax and php, which will ask for username and password. It checks the value of the 'message' variable to see if it is to be submitted or not.

test.php

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
    <script src="ecommercescript.js" defer="true"></script>
 </head>
<body>
    <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#login">Sign In</button>
    <div id="login" class="modal fade" role="dialog">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Sign In With Your Account</h4>
                </div>
                <div class="modal-body">
                    <form id="loginForm" class="form-horizontal" role="form" action="login.php" method="post" onsubmit="return validateForm()">
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="usr">Username:</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="usr" placeholder="Enter your username" name="usr">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="pwd">Password:</label>
                        <div class="col-sm-10">
                            <input type="password" class="form-control" id="pwd" name="pwd" placeholder="Enter your password">
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-sm-offset-4">
                            <label id="prompt" class="control-label">&nbsp;</label>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-sm-offset-4 col-sm-10">
                            <button type="submit" class="btn btn-primary">Submit</button>
                            <button type="button" class="btn btn-primary" onclick="clearInput()">Cancel</button>
                       </div>
                    </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

ecommercescript.js

function validateForm() {
    var usr = document.forms["loginForm"]["usr"].value.trim();
    var pwd = document.forms["loginForm"]["pwd"].value.trim();
    var message = "";
    var validity = true;

    if (usr.length > 0 && pwd.length > 0) {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                message = xmlhttp.responseText;
                document.getElementById('prompt').innerHTML = message;
            }
        }
        //value of 'message' gets lost here
        xmlhttp.open("POST", "searchuser.php", true);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp.send("username="+usr+"&password="+pwd+"")
    } else {
        message = "Username and/or password must be filled out";
        document.getElementById('prompt').innerHTML = message;
        validity = false;
    }

    if (message.length > 0) {
        validity = false;
    }

    return validity;
}
function clearInput() {
    document.getElementById('usr').value = "";
    document.getElementById('pwd').value = "";
}

searchuser.php

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "ecommerce";

//Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

//Check connection
if ($conn->connect_error) {
    die("Database connect failed: " . $conn->connect_error);
}

$username = $_REQUEST["username"];
$password = $_REQUEST["password"];
$message = "Account does not exist";

$sql = "SELECT * FROM tbl_users";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
        if ($row['username'] == $username and $row['password'] == $password) {
            $message = "";
            break;
        } else if ($row['username'] == $username and $row['password'] != $password) {
            $message = "Incorrect password";
        }
    }
} 

$conn->close();
echo $message;
?>

My problem is that the value of 'message' inside xmlhttp.onreadystatechange gets lost so that the script cant validate and will always submit the form. I have commented the part where it gets lost. Need your help about this.

Pang
  • 9,564
  • 146
  • 81
  • 122
  • the message variable isn't lost. `onreadystatechange` is an event listener so it will trigger/fire when the event is taken place. Meaning `message` will only = to `xmlhttp.responseText` when the `onreadystatechange` changes and is true to your if condition `xmlhttp.readyState == 4 && xmlhttp.status == 200` Could it be possible you have one too many `}` or `}else{` ? – NewToJS May 27 '15 at 02:34
  • To be clear, an AJAX request takes time to send the request and receive a response. But the browser doesn't stand around waiting for the response. Instead, it keeps executing code after it. This is called async. So, your code that looks for the variable is executed before the AJAX call has been complete. It's like sending your kid out to check the mail but trying to open the mail before your kid has returned from the mailbox! So basically, you need to restructure your code to execute after the response has been received (see answers below) – CrayonViolent May 27 '15 at 02:44

3 Answers3

0

You basically have this:

When done with HTTP request {
    Do a bunch of stuff;
    Set message variable;
}
// comment about lost variable
Code to send HTTP request;
if (some stuff about message){
   More stuff;
}

The code that sets message will be run after you send the request. Furthermore, the code that validates the length of message will run before your HTTP request is resolved (I think this is always true, but maybe a fast network can beat the JS to the condition? Feel free to edit if you know).

The way to resolve this is:

When done with HTTP request {
    Do a bunch of stuff;
    Set message variable
    if (some stuff about message){
       More stuff;
    }
}
// comment about sending request
Code to send HTTP request;

Hope this help!

sudo rm -rf slash
  • 1,156
  • 2
  • 16
  • 27
0

Its not getting lost, you're trying to use an async variable before it is set. If you want to do it this way you need promise objects. q.js is a really good one.

function validateForm() {
    var deferred = Q.defer();
    var usr = document.forms["loginForm"]["usr"].value.trim();
    var pwd = document.forms["loginForm"]["pwd"].value.trim();
    var message = "";
    var validity = true;

    if (usr.length > 0 && pwd.length > 0) {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                message = xmlhttp.responseText;
                document.getElementById('prompt').innerHTML = message;
                deferred.resolve(message);
            }
        }
        //value of 'message' gets lost here
        xmlhttp.open("POST", "searchuser.php", true);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp.send("username="+usr+"&password="+pwd+"")

    } else {
        message = "Username and/or password must be filled out";
        document.getElementById('prompt').innerHTML = message;
        deferred.resolve(message);
    }

    return deferred.promise;
}

Or emit a custom event when the xmlhttprequest resolves

function validateForm() {
    var customEvent = new Event('messageResolved');
    var usr = document.forms["loginForm"]["usr"].value.trim();
    var pwd = document.forms["loginForm"]["pwd"].value.trim();
    var message = "";
    var validity = true;

    if (usr.length > 0 && pwd.length > 0) {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                message = xmlhttp.responseText;
                document.getElementById('prompt').innerHTML = message;
                document.dispatchEvent('messageResolved', { message: message });
            }
        }
        //value of 'message' gets lost here
        xmlhttp.open("POST", "searchuser.php", true);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp.send("username="+usr+"&password="+pwd+"")

    } else {
        message = "Username and/or password must be filled out";
        document.getElementById('prompt').innerHTML = message;
        document.dispatchEvent('messageResolved', { message: message });
    }
} 

Or use a callback

function validateForm() {
    var usr = document.forms["loginForm"]["usr"].value.trim();
    var pwd = document.forms["loginForm"]["pwd"].value.trim();
    var message = "";
    var validity = true;

    if (usr.length > 0 && pwd.length > 0) {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                message = xmlhttp.responseText;
                document.getElementById('prompt').innerHTML = message;
                callback(message);
            }
        }
        //value of 'message' gets lost here
        xmlhttp.open("POST", "searchuser.php", true);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp.send("username="+usr+"&password="+pwd+"")

    } else {
        message = "Username and/or password must be filled out";
        document.getElementById('prompt').innerHTML = message;
        callback(message);
    }
}

function callback(message){

}
Kevin F
  • 2,836
  • 2
  • 16
  • 21
0

Thanks though, i manage to make it work by setting the async parameter to false. Thank you for your insights anyway.

before

 //value of 'message' gets lost here
 xmlhttp.open("POST", "searchuser.php", true);

after

//value of 'message' gets lost here
 xmlhttp.open("POST", "searchuser.php", false);