How to send an ajax request on form submit without affecting the actual form

Viewed 128

I want to create a signup form that will validate your input and then send an AJAX request to a PHP page to check if your username has already been used. After that it will submit the actual form (the location is in an action attribute).

function validate() {
  if (fullname.length < 90) { /*this is validating the form*/
    var username_input = document.forms["myform"]["username"].value;
    if (window.XMLHttpRequest) {
      var usernamecheck = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      var usernamecheck = new ActiveXObject("Microsoft.XMLHTTP");
    }
    usernamecheck.open("POST", "reciever.php", true);
    usernamecheck.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    usernamecheck.send("user=" + username_input); /*sending username to check if it exists*/
    usernamecheck.onreadystatechange = function() {
      if (usernamecheck.readyState == 4 && this.status == 200) {
        if (usernamecheck.responseText == "user") {
          alert('username has already been used');
          return false;
        }
      }
    };

    var contactcheck = new XMLHttpRequest(); /*second request*/
    contactcheck.open("POST", "reciever.php", true);
    contactcheck.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    contactcheck.send("contact=" + contactw);
    contactcheck.onreadystatechange = function() {
      if (contactcheck.readyState == 4 && this.status == 200) {
        if (contactcheck.responseText == "contact") {
          alert('email has already been used');
          return false;
        }
      }
    };
  }
  /*reference 1 (see below)*/
}

My problem is that the form submits even before the AJAX runs, and if I add return false; where the script says ‘reference 1’ the AJAX runs, but the form does not submit.

2 Answers

Your question is similar to this one:

check if username exists in real-time through AJAX in php with mysql

Quoting the post:

"Send your data in javascript using jQuery like this:"

$.post( "check.php", { user: $("#username").val() }, function (data){
  if(data=='1'){
   //do 1
  }
  elseif(data=='0'){
    //do 0
  }
});

In your check.php get username like this

//some basic validation
if(!isset($_POST['user'] || empty($_POST['user']))
{

       echo '0'; exit();
    }

$username = trim($_POST['user']); 

"For this to work properly you check.php must return either 1 or 0, do not echo mysql errors there or whatsoever. if any error occur, just echo 0."

If your function is used as an event handler, like addEventListener('submit', validate) or onsubmit="validate()" then you should check the Event object send with the submit event and prevent the default submit behavior of the form.

You can do that with the event.preventDefault() method which, like it says, prevents the default behavior of the form, which is submitting.

But the reason why your return false statements are not working, are because of the asynchronous nature of XMLHttpRequest.send(). This means that the function will not wait for the return statement because it is inside a function that is called way later. The reason for his behavior is to let other code run while you wait for a response for the server instead of holding up the code until the request has finished.

You also can send multiple values to the server in a single request instead of doing two separate requests. AJAX requests should be optimized as much as possible as they (can be) taxing on both the client and server.

See the snippets below to see how you could do all the above.

function validate(event) {
  if (fullname.length >= 90) {
    return; // Stop function if condition is not met.
  }
  event.preventDefault(); // Prevent form from submitting.
  var form = event.target; // The target is the form that is submitting.
  var userName = form.elements['username'].value;
  var email = form.elements['email'].value; // I assume this was missing.
  var request;
  if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
  } else if (window.ActiveXObject) {
    request = new ActiveXObject("Microsoft.XMLHTTP");
  }
  request.open("POST", "reciever.php", true);
  request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  request.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var response = this.responseText;
      if (response === "user") {
        alert('Username has already been used');
      } else if (response === "email") {
        alert('Email has already been used');
      }
    }
  };
  request.send('user=' + userName + '&email=' + email); // Send both user name and email values.
}

It seems that you use legacy code like ActiveXObject which is not used anymore by current browsers. If you really need it for older browsers, then you're good. If you care for a more modern approach and don't need to support old browsers then look at the example below. It (almost) does the same thing, but with a different syntax.

const alerts = {
  'user': 'Username has already been used',
  'email': 'Email has already been used'
};

async function validate(event) {
  if (fullname.length >= 90) return; 
  event.preventDefault();
  const formData = new FormData(event.target);
  try {
    const response = await fetch('reciever.php', {
      method: 'POST',
      body: formData
    }
    if (!response.ok) {
      throw new Error(`
        Check has failed. - 
        ${response.status}: 
        ${response.statusText}`
      );
    }
    const text = await response.text();
    if (text in alerts) alert(alerts[text]);
  } catch (error) {
    console.error(error);
  }
}

Related