Building a Sleek AJAX Email Signup Form

Building a Sleek AJAX Email Signup Form

Tutorial Details
  • Languages: PHP, MySQL, jQuery
  • Difficulty: Beginner - Intermediate
  • Estimated Completion Time: 45 - 60 Minutes

Final Product What You'll Be Creating

In this tutorial, we’ll learn how to create a slick email signup form. This form will harness the full power of AJAX, meaning that we will submit data to the server, validate it, and receive a response – all without a single page refresh! Along the way, you should pick up some useful tips related to PHP and JavaScript, as well as general programming best practices.



Step 1: The Plan

So, we want to create an email signup form, but not just any signup form: we want to create a super-responsive, AJAX-powered email signup form. This means no pesky page refreshes, giving the end user real-time status updates, and all the juicy goodness of server side data validation. Here is a flow chart of exactly how we want this to work:

Flow Chart Of Events

To accomplish all this hocus pocus, we’ll need to use some pretty cool web technologies. These include JavaScript (with a little lot of help from jQuery), AJAX, PHP, MySQL and JSON. Heres a rundown of what we will be using each technology for:

  • JavaScript – Submit data to the server and parse messages received from the server. We will be using jQuery to handle our AJAX calls and parse our JSON.
  • PHP – Process the data sent to the server. This will include validating the data (making sure it’s OK to put in the database) and handling the response to send back to the browser.
  • MySQL – Store the signup data.
  • JSON – Glue all of the above together. I will explain more about JSON later in this tutorial.

So we know how we want it to work, and we know what technologies we want to use: it’s time to get started!


Step 2: Setting Up the MySQL Database

Ok, first things first: we need to set up our database. At the moment the only data we want to record is the user’s email address, and the date and time he or she signed up. Open up PHPMyAdmin (or whatever program you use to manage your MySQL database) and create a new table in your database using the following statement:

CREATE TABLE `signups` (
  `signups_id` int(10) NOT NULL AUTO_INCREMENT,
  `signup_email_address` varchar(250) DEFAULT NULL,
  `signup_date` date DEFAULT NULL,
  `signup_time` time DEFAULT NULL,
  PRIMARY KEY (`signups_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

The above should be sufficient for what we need. signups_id is an auto incrementing field to assign a unique id to each record, signup_email_address is a varchar field and will be the email address the user uses to sign up with, and signup_date and signup_time are date and time fields which will record when the user signed up. Next, we need to set up the HTML.


Step 3: Setting up the HTML

<form id="newsletter-signup" action="?action=signup" method="post">
    <fieldset>
        <label for="signup-email">Sign up for email offers, news & events:</label>
        <input type="text" name="signup-email" id="signup-email" />
        <input type="submit" id="signup-button" value="Sign Me Up!" />
        <p id="signup-response"></p>
    </fieldset>
</form>

This should be the bare minimum HTML that we need to get this working (I have not included the body tags or header stuff in this snippet just to save space. Do note that you will need to have jQuery loaded on your page). All we need is a text input, a submit button, and a message placeholder. Obviously, you need a label for the input, and I have used a fieldset as I am working with an XHTML strict doctype. The placeholder is where our status message to the user is going to be shown. At the moment it should just be empty.

Unstyled Form

So here’s our form in all its glory. Looks pretty plain, doesn’t it? I’m going to do some CSS for our form to make it look a little less windows95-ish.

* {
    padding:0;
    margin:0;
}

body {
    font-size:12px;
    font-family:Arial, Helvetica, sans-serif;
}

fieldset {
    border:none;
}

form {
    width:930px;
    margin:20% auto;
    padding:15px;
    border:solid 6px #9FCBFF;
    -moz-border-radius:6px;
    -webkit-border-radius:6px;
    border-radius:6px;
}

input {
    border:none;
    background-color:none;
}

#signup-email {
    border:1px solid #999999;
    color:#9E9E9E;
    padding:5px;
    margin-left:10px;
    margin-right:4px;
}

#signup-email:focus {
    border-color:#9FCBFF;
    background-color:#DFEEFF;
    background-image:none;
    color:#000;
}

#signup-button {
    background-color:#9FCBFF;
    color:#FFF;
    -moz-border-radius:10px;
    -webkit-border-radius:10px;
    border-radius:10px;
    padding:5px;
    text-shadow: 1px 1px 1px #5FA8FF;
}

#signup-button:hover {
    cursor:pointer;
    background-color:#7FB9FF;
}

#signup-response {
    display:inline;
    margin-left:4px;
    padding-left:20px;
}

.response-waiting {
    background:url("loading.gif") no-repeat;
}

.response-success {
   background:url("tick.png") no-repeat;
}

.response-error {
   background:url("cross.png") no-repeat;
}
Styled Form

That’s better. Although our response message is not yet visible (as there in no response yet) it will appear next to the “sign me up” button like so:

Form With Message


Step 4: The Glue

Now that the database access and mark-up have been completed, we need to know how we are going to link the two together.

How is the JavaScript going to be able to send and receive messages from a completely different programming language (PHP)? We are going to use something called JSON.

What is JSON?

JSON (JavaScript Object Notation) is a lightweight, text-based open standard designed for human-readable data interchange (similar to XML in intent). JSON is often used for serializing and transmitting structured data over a network connection. It is primarily used to transmit data between a server and web application, serving as an alternative to XML. JSON is derived from the JavaScript programming language for representing simple data structures and associative arrays, called objects. Despite its relationship to JavaScript, it is language-independent, with parsers available for virtually every programming language. Yep, that includes PHP. Here is a snippet of JSON:

{"hey I'm a key":"and I'm its value!"}

As you can see it’s super-simple. We have encapsulated a key-value pair in some curly braces. The key-value pair relationship is indicated using a colon. The curly braces indicate that this is an object, and everything inside of them is part of that object. You can have multiple key-value pairs in an object:

{"hey I'm a key":"and I'm its value!",
 "hey I'm another key":"and I'm its value!",
 "you guessed it, I'm a key":"and I'm its value!"}

All we have done is split the key-value pairs using a comma. The key-value pairs are actually referred to as members of the object (the JSON object). You can get even more fancy and have an array as a value of a key which holds more objects

{"key1": {
  "key2": "value2",
  "key3": "value3",
  "key4": {
    "value4": [
      {"newobject_1_key_1": "newobject_1_value_1", "newobject_1_key_2": "newobject_1_value_2"},
      {"newobject_2_key_1": "newobject_2_value_1", "newobject_2_key_2": "newobject_2_value_2"},
      {"newobject_3_key_1": "newobject_3_value_1", "newobject_3_key_2": "newobject_3_value_2"}
     ]
  }
}}

Let’s go through this:

  • Key1′s value is an object.
  • Inside that object there are key-value pairs for key2 and key3.
  • Key4 has an object for its value.
  • Value 4 is an array of 3 more objects, which contain 2 key-value pairs each.

But that’s getting too complicated for our needs.

All we are going to need to do is get the server to send us a JSON response containing two members (key-value pairs): one for the status and one for the message. This will look like so:

{"status":"success","message":"Wahey! You've been signed up!"}

status will indicate whether the signup process was successful or not. message will be the message related to the status. If the status is ‘success’ we want to tell the user they are signed up. If the status is ‘error’, then we want to tell the user what went wrong. So if we’re telling the user what has happened via the message member, why do we need the status member? Well, there are two reasons. The first is that we want to apply a class to the response message holder, so that we display a green tick for success and a red cross for an error. The second reason is there can be only one success message that can be sent back (indicating the user has been signed up), but there are up to four error messages that could be sent back. Error messages will occur in the following cases:

  • The user did not enter an email address.
  • The user entered an invalid email address.
  • The email address the user entered has already been used.
  • There is some kind of technical error and the user can not be validated or added to the database.

This means that we also need to know the exact text responses of each message, in order to assign the correct class to the message holder. This equals one massive headache. What if we wanted to change the message sent back? We would then need to revise the code used to assign the class to the message holder as well. It is so much easier to send back the status.

Don’t worry if you do not understand this JSON malarkey yet; as we work

Premium Members: Download this Video ( Must be logged in)

through the rest of the tutorial, it should start to piece together.


Step 5: Preparing It All

Normally, when you submit a form, the browser is redirected to the action of the form. We don’t want this to happen, as we want to submit data in the form using AJAX. The first thing we need to do is stop the form from redirecting us when the submit button is clicked.

$(document).ready(function(){
   $('#newsletter-signup').submit(function(){

        //do our ajax stuff here

        //prevent form from submitting
        return false;
    })
})

Here, we are saying, “when document is ready and the submit event is triggered for any element with an id of newsletter-signup (which just happens to be our form), execute the code inside the function.” This is where we will be inserting the AJAX call, the JSON response handler, and anything else needed to make our form function the way we wish. The only code in this function at the moment is return false. This will stop the form from submitting, which in turn stops it from redirecting us. The next thing we need to do is set up the variables that we are going to be using.

var form = $(this),
    formData = form.serialize(),
    formUrl = form.attr('action'),
    formMethod = form.attr('method'),
    responseMsg = $('#signup-response')

Here we are declaring multiple variables all at once. It just saves writing the var keyword five times. Good times. Anyhow, here is what each variable is for:

  • form – We use the this keyword wrapped in the jQuery object. this refers to the actual form element. We want to wrap it in the jQuery object so we can use other jQuery DOM functions.
  • formdata – We are using the jQuery serialize() function to get all the form data. In its simplest form serialize() gets all the form fields and all their values and puts them in key-value pairs inside a string. We will then send this string of data to the server.
  • formUrl – This is the URL we want to send our data to.
  • formMethod – This is the method we want to use to send our data.
  • responseMsg – This is the element that we are going to use to display our message to the user.

We get the form URL and form method this way so we don’t have to change the JavaScript if we decide to change where and how we send the data to the server in the HTML. We store the response message element in a variable so we only have to search the DOM for it once. To continuously query the DOM for an element is wasteful.

As we are going to be using AJAX to submit the form, we should provide the end user an indication that we are doing some work behind the scenes, so to speak. To do so, we will set the response message holders text to ‘Please Wait…’ and give it a class of ‘response-waiting’. This will give it a cool loading gif :).

//show response message - waiting
responseMsg.hide()
           .addClass('response-waiting')
           .text('Please Wait...')
           .fadeIn(200);

We hide the response message holder first so that when we set the text, it does not show straight away. Next, we add the class ‘response-waiting’. After that, we set the text to ‘Please Wait…’ and finally fade it in. All we are doing here is chaining together jQuery functions. The responseMsg code could be wrote on one line; I’ve just split it up to make it easier to read.

responseMsg.hide().addClass('response-waiting').text('Please Wait...').fadeIn(200);


Step 6: Submitting To The Server

Okay, it’s time to get to the juicy bit. Now that we have our data, and have provided some visual feedback to the visitor, we’ll use a jQuery function to submit the data to the server.

$(document).ready(function(){
    $('#newsletter-signup').submit(function(){

        //setup variables
        var form = $(this),
        formData = form.serialize(),
        formUrl = form.attr('action'),
        formMethod = form.attr('method'),
        responseMsg = $('#signup-response')

        //show response message - waiting
        responseMsg.hide()
                   .addClass('response-waiting')
                   .text('Please Wait...')
                   .fadeIn(200);

        //send data to server
        $.ajax({
            url: formUrl,
            type: formMethod,
            data: formData,
            success:function(data){
                //do something when ajax call is complete
            }
        })

        //prevent form from submitting
        return false;
    })
})

The magic happens here:

$.ajax({
    url: formUrl,
    type: formMethod,
    data: formData,
    success:function(data){
        //do something we ajax call is complete
    }
})

We are using the jQuery function $.ajax() to submit the data to the server. This function handles all the complicated cross browser XML HTTP Request stuff that we’re not really interested in. Notice something here? Looks a lot like a JSON object…

We need to pass some information to the $.ajax() function so it knows what to do and how to do it. You can pass multiple parameters to the $.ajax() function, but for the sake of this tutorial, we only need to pass it the url, type, data and success parameters.

  • url – This is the url we want to send our data to. We saved this in a variable called formURL earlier.
  • type – This is the method we want use to send our data to the server. We saved this in a variable called formMethod earlier.
  • data – This is the data we want to send to the server. We saved this in a variable called code>formDataearlier
  • success - This is a callback function. It is called if the AJAX call is successful. In this function we will process the JSON response we get from the server.


Step 7: The Success Function

Once we have submitted the data to the server, it will send us a response message back. The message will be a well formatted JSON string. Luckily for us, jQuery has a neat function to parse JSON.

success:function(data){

    //setup variables
    var responseData = jQuery.parseJSON(data),
        klass = '';
}

The argument data that is passed to the success function is our JSON response returned from the server. Within this function, the first thing we want to do is setup two variables:

  • responseData - This will hold the parsed JSON response. The $.parseJSON() function will turn our JSON response into a JavaScript object.
  • klass - This will be a variable that we will set later. It will contain the name of the class we want to apply to the response message holder, based on the response we receive from the server. If you are wondering why we are calling the class variable klass, it is because the word 'class' is a reserved word in JavaScript and can not be used as a variable name.

The next thing must do is determine which CSS class we should apply to the response message holder. The class will be based on what status the server returns. If the status is 'success,' we want to give it a class of 'response-success,' and if the status is 'error,' we'll give it a class of 'response-error'

//response conditional
switch(responseData.status){
    case 'error':
        klass = 'response-error';
    break;
    case 'success':
        klass = 'response-success';
    break;
}

The CSS classes that will be applied to the status messages will look like:

Response Classes

The first one is the loading message (.response-loading), the second is the success message (.response-success) and the third is the error message (.response-error).

We are using a switch statement to determine which class to use based on the status. I could have used if statements, but this is a better way of doing it. The condition we want to compare against is responseData.status. responseData is an object and status is a property of that object. This object was created by the $.parseJSON() function and is based on our JSON response. This response will return two members: status and message. These will be converted into properties of the responseData object. In this switch, we have two cases to compare responseData.status against. If responseData.status is equal to the string 'error', then the klass variable will be set to 'response-error'. If responseData.status is equal to the string 'success' , then the klass variable will be set to 'response-success'. Now all that is left to do is actually show the message to the user.

//show reponse message
responseMsg.fadeOut(200,function(){
    $(this).removeClass('response-waiting')
           .addClass(klass)
           .text(responseData.message)
           .fadeIn(200,function(){
               //set timeout to hide response message
               setTimeout(function(){
                   responseMsg.fadeOut(200,function(){
                       $(this).removeClass(klass);
                   });
               },3000)
            })
})

The first task we do is fade out the response message holder, as it is currently set to 'Please Wait...'. Once this has been completed, we remove the class 'response-waiting', add either the 'error' or 'success' class, set the text to be the message sent back from the server, and then finally fade it back in. All of this is done from the callback of the fadeOut() function. Once the message has faded in, we don't want it to stick around forever so we set a timeout to fade the message out again after three seconds. This is all done from the callback of the fadeIn() function.

As you can see, we are making good use of jQuery's callback functions. These ensure that everything is executed in the correct order, at the correct time. If we did not use the callback functions, we would end up in a situation where we fade the message in and immediately tell it the fade out even though it has not finished fading in. Finally, when the response message holder has faded out we want to remove any classes we assigned to it. That's it for the success function!

And that's it for the JavaScript, too. We have set up our variables, set our status message, submitted the data via AJAX, got a JSON response, parsed the JSON, and returned the status of the submission back to the user. Your completed JavaScript code should look like so:

$(document).ready(function(){
    $('#newsletter-signup').submit(function(){

        //setup variables
        var form = $(this),
        formData = form.serialize(),
        formUrl = form.attr('action'),
        formMethod = form.attr('method'),
        responseMsg = $('#signup-response');

        //show response message - waiting
        responseMsg.hide()
                   .addClass('response-waiting')
                   .text('Please Wait...')
                   .fadeIn(200);

        //send data to server for validation
        $.ajax({
            url: formUrl,
            type: formMethod,
            data: formData,
            success:function(data){

                //setup variables
                var responseData = jQuery.parseJSON(data),
                    klass = '';

                //response conditional
                switch(responseData.status){
                    case 'error':
                        klass = 'response-error';
                    break;
                    case 'success':
                        klass = 'response-success';
                    break;
                }

                //show reponse message
                responseMsg.fadeOut(200,function(){
                    $(this).removeClass('response-waiting')
                           .addClass(klass)
                           .text(responseData.message)
                           .fadeIn(200,function(){
                               //set timeout to hide response message
                               setTimeout(function(){
                                   responseMsg.fadeOut(200,function(){
                                       $(this).removeClass(klass);
                                   });
                               },3000);
                            });
                 });
              }
        });

        //prevent form from submitting
        return false;
    });
});


Step 8: Server Side Validation

Now that we have the HTML prepared, and the JavaScript ready to send and receive data, we need to write our server side code to process the data it's given, and send a JSON response back to the JavaScript. For this tutorial, PHP will be our server-side language of choice.

if($_GET['action'] == 'signup'){
    mysql_connect('localhost','YOUR DB USERNAME','YOUR DB PASSWORD');
    mysql_select_db('YOUR DATABASE THAT CONTAINS THE SIGNUPS TABLE');
    $email = mysql_real_escape_string($_POST['signup-email']);

    //do some stuff

    exit;
}

Here we are saying that if, in the querystring, (as we are using the $_GET array) the parameter action is equal to 'signup,' then execute this code. This is a good way to encapsulate our AJAX call. Firstly we define our MySQL connection using PHP's built in mysql_connect() function. To get this connected to our database we need to give it the host, the database user username, and the database user password. We don't have to do any error checking here, as we are going to do that later in the script. Next, we select the database we want to access using mysql_select_db().

Now that we have got our database access code set up, we can use the mysql_real_escape_string() function to sanitize the data we are sending to the server. This makes the data safe for inserting into the database by escaping certain characters that are classed as unsafe. Because we are posting the data to the server, we use the $_POST array to access our email address. $_POST['signup-email'] will get our email address and we will store it in a variable called $email. The last line of code is the exit statement. This will stop the rest of the script from executing. This is useful if we had lots of code in here, as we only want to run the bit we need and ignore the rest. This is important to keep our AJAX calls nice and speedy. The next thing we are going to need to do is validate the data to make sure that we are not inserting any old junk into the database.

//validate email address - check if input was empty
if(empty($email)){
    $status = 'error';
    $message = 'You did not enter an email address!';
}
else if(!preg_match($emailRegex, $email)){ //validate email address - check if is a valid email address
    $status = 'error';
    $message = 'You have entered an invalid email address!';
}
else {
    $existingSignup = mysql_query("SELECT * FROM signups WHERE signup_email_address='$email'");
    if(mysql_num_rows($existingSignup) < 1){

        //database insert code

    }
    else {
        $status = 'error';
        $message = 'This email address has already been registered!';
    }
}

We only need to do three checks on our data:

  1. Make sure the user actually submitted an email address
  2. Make sure the email address submitted is a valid email address
  3. Make sure the email address submitted has not already been used to sign up

We are using a series of if statements to achieve this. The first if uses the PHP function empty() to check if the $email variable actually contains anything. If the variable is equal to an empty string, 0, '0', false or null, it will return true (meaning that we have an empty variable). If we have an empty variable, we set a variable called $status to 'error' and a variable called $message to 'You did not enter an email address!'. If our variable is not empty we can proceed to check that it is a valid email address. To do so, we use a PHP function called preg_match(). We give this function a regular expression (the long string full of weird characters) and our email address. If the email address matches the regular expression, the function returns 1 (which equates to true). If it does not match, it returns 0 (which equates to false). In our case if preg_match() returns false, we know the email address is invalid; so we set our $status variable to equal 'error' and our $message variable to equal 'You have entered an invalid email address!'. Otherwise if preg_match() returns true, we can move on to the next check which requires us querying the database to see if our email address has already been signed up. We can use the PHP function mysql_query(), which accepts a SQL query, queries the database, and returns a resource. We do not need to know anything about the data that mysql_query() returns; we only need to know how many records is returned. If it returns more than 0, this email address has been used to sign up before so we set our $status and $message variables accordingly. If no records are returned, we are good to insert our data into the database.

We use the PHP function mysql_num_rows() to find out how many records the query returned. All we need to do is pass it the resource which we saved in a variable called $existingSignup and it will return a number. We then use an if statement to check that the number is less than 1.


Step 9: Insert Into Database

We have verified our data is OK to be put in the database, so we are going to use the following code to so:

$date = date('Y-m-d');
$time = date('H:i:s');

$insertSignup = mysql_query("INSERT INTO signups (signup_email_address, signup_date, signup_time) VALUES ('$email','$date','$time')");
if($insertSignup){
    $status = 'success';
    $message = 'you have been signed up!';
}
else {
    $status = 'error';
    $message = 'Oops, there's been a technical error! You have not been signed up.';
}

The date and time variables are PHP functions that return the date and time in a specified format. Because we set the signup_date field in the database to be a date field and the signup_time field to be a time field, I am formatting my date and time to suit them. The next thing to do is insert the data into the database. This, again, is done by using the mysql_query() function and passing it an SQL statement. Because this is an INSERT SQL statement, the function will return true on success and false on failure. It will not return a resource as there is no resource to return because we were just executing a statement. We then check if the query was successful or not. If it was, we set our $status variable to 'success' and our $message variable to 'you have been signed up!'. Otherwise, if the query failed, we set $status to 'error' and $message to 'Oops, There's been a technical error! You have not been signed up.' We don't need to tell the user what the error was, just that there's been a problem and they have not been signed up. This will also catch any error caused by the initial connection code (like could not connect to database or could not find table, etc).


Step 10: Send The Response Back

The previous step defined two variables: $status and $message. This is the data we want to encode as JSON to send back to the user. We are going to put these two variables into an associative array, so we can provide meaningful names to the keys of the JSON members.

$data = array(
    'status' => $status,
    'message' => $message
);

You don't have to write your associative array like this; though I personally find it easier to read. All we need to do now is pass this array to a PHP function called json_encode(). This turns our associative array into a well formatted JSON string. Once it has been encoded as JSON, we need to return it back to the clients browser. We do this with a simple echo statement.

echo json_encode($data);

And that's it. That's all the server side code needed. You should have ended up with this:

if($_GET['action'] == 'signup'){
    mysql_connect('localhost','YOUR DB USERNAME','YOUR DB PASSWORD');
    mysql_select_db('YOUR DATABASE THAT CONTAINS THE SIGNUPS TABLE');

    //sanitize data
    $email = mysql_real_escape_string($_POST['signup-email']);

    //validate email address - check if input was empty
    if(empty($email)){
        $status = "error";
        $message = "You did not enter an email address!";
    }
    else if(!preg_match('/^[^\W][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\@[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\.[a-zA-Z]{2,4}$/', $email)){ //validate email address - check if is a valid email address
        $status = "error";
        $message = "You have entered an invalid email address!";
    }
    else {
       $existingSignup = mysql_query("SELECT * FROM signups WHERE signup_email_address='$email'");
       if(mysql_num_rows($existingSignup) < 1){

           $date = date('Y-m-d');
           $time = date('H:i:s');

           $insertSignup = mysql_query("INSERT INTO signups (signup_email_address, signup_date, signup_time) VALUES ('$email','$date','$time')");
           if($insertSignup){
               $status = "success";
               $message = "You have been signed up!";
           }
           else {
               $status = "error";
               $message = "Ooops, Theres been a technical error!";
           }
        }
        else {
            $status = "error";
            $message = "This email address has already been registered!";
        }
    }

    //return json response
    $data = array(
        'status' => $status,
        'message' => $message
    );

    echo json_encode($data);

    exit;
}

That is all the code we need for the email signup form to work. Hopefully, if you followed this tutorial step by step you, should be recording email signups now. Although our code works and our form does what it should, there is one last thing that will improve the form.

If the user clicks the submit button more than once before the AJAX call has finished, we are going to get some pretty weird results. The message results holder will fade in and fade out again, but the timeout won't reset. This will look daft, as well as causing unnecessary calls to the server. Really, we should stop the user from submitting the form whilst a submission is currently in progress.


Step 11: Stopping Multiple Form Submissions

Stopping multiple form submissions is actually pretty easy to accomplish. All we need to do is check what the form's status is when it is submitted. If it is currently submitting, we don't want to re-submit the form until it has finished. To do this, we'll store the status of the form, on the form, using jQuery's data() function. This function lets us store and retrieve arbitrary data associated with the matched element in key value format. We will use a key called 'formstatus' and its value will either be 'submitting' or 'idle'. If 'formstatus' equals 'submitting,' the form will not be submitted. If it equals 'idle', it will submit. Once the form is submitted, we will need to set 'formstatus' to 'submitting'. And, when ithas finished submitting, we set 'formstatus' to 'idle'. Here's our final JavaScript.

$(document).ready(function(){
    $('#newsletter-signup').submit(function(){

    //check the form is not currently submitting
    if($(this).data('formstatus') !== 'submitting'){

         //setup variables
         var form = $(this),
         formData = form.serialize(),
         formUrl = form.attr('action'),
         formMethod = form.attr('method'),
         responseMsg = $('#signup-response');

         //add status data to form
         form.data('formstatus','submitting');

         //show response message - waiting
         responseMsg.hide()
                    .addClass('response-waiting')
                    .text('Please Wait...')
                    .fadeIn(200);

         //send data to server for validation
         $.ajax({
             url: formUrl,
             type: formMethod,
             data: formData,
             success:function(data){

                //setup variables
                var responseData = jQuery.parseJSON(data),
                    klass = '';

                //response conditional
                switch(responseData.status){
                    case 'error':
                        klass = 'response-error';
                    break;
                    case 'success':
                        klass = 'response-success';
                    break;
                }

                //show reponse message
                responseMsg.fadeOut(200,function(){
                   $(this).removeClass('response-waiting')
                          .addClass(klass)
                          .text(responseData.message)
                          .fadeIn(200,function(){
                              //set timeout to hide response message
                              setTimeout(function(){
                                  responseMsg.fadeOut(200,function(){
                                      $(this).removeClass(klass);
                                      form.data('formstatus','idle');
                                  });
                               },3000)
                           });
                });
           }
      });
    }

    //prevent form from submitting
    return false;

    });
})


Conclusion

Hopefully, you can apply the techniques you've learned in this tutorial to create more complex projects in the future. Thanks for reading, and, if you have any questions or comments, don't hesitate to leave a comment below.

Styled Form

Michael Barrett is mike182uk on Codecanyon
Add Comment

Discussion 98 Comments

Comment Page 1 of 21 2
  1. Jacob says:

    Great tutorial! Thanks for posting such an extensive, thorough and complete tutorial.

    Step 9, Line 11 has an error. You used a single quote in the string response.

    • Koren Berman says:

      That’s right, should escape it:
      $message = ‘Oops, there\’s been a technical error! You have not been signed up.’;

      But anyways good tutorial, very thorough. It was interesting to read about AJAX in JSON output, since xml seems to be the usual choice.

      How about a follow-up tutorial on how to automatically send emails to subscribers whenever new content is posted?

    • Author

      My bad! It was a test 2 make sure you guys were reading it properly ;) …

  2. Nelson says:

    great article…support~~

  3. DesignMango says:

    very nice tut, thanks

  4. Jeff Adams says:

    Excellent tutorial, something like this was really needed on the site because these are more real-world examples folks can learn from.

    Well done.

  5. Ryan Sukale says:

    Great Tutorial.
    Really helpful and clear :)

  6. Matthew says:

    This gave me some great insight on JSON, thanks!

  7. Great tutorial, really informative.

    I’ve been wrestling with JSON for a while, and I can’t believe it’s so easy! (seriously, I was having huge troubles)

    Just wondering, shouldn’t there be a timeout set in the $.ajax call, it’d make life much easier if the user didn’t just see these endlessly spinning timers.

    Perhaps a variable setup where you start at say, 3 tries, and each unsuccessful call reduces that number, and if that number is 0 or less, you ask the user to please refresh the page, or something similar.

  8. w1sh says:

    Can a dev get a demo in hurr?!

  9. patrick says:

    Great tutorial that gives something more about AJAX, jQuery, PHP and JSON! Thank You very much; clear and simple!

  10. Dennis L says:

    Great article, very detailed! One thing, it’s better to provide a Legend with the Fieldset tag to define what the (portion of) the form is. For example: Newsletter Signup

  11. amarullz says:

    Wow… Great Tutorial.. Thanks

  12. Dj says:

    Yes… I second the request for a follow-up article — except that It might be good for two:

    One – a second step which sends out a confirmation email to the signee for confirmation/identification purposes THEN finalizes the sign-up upon receiving the confirmation number; and,

    Two – the bulk emailer for those wishing to receive notifications.

    Thanks again… this is a really good tut.

  13. chivy says:

    Well said. I never thought I would agree with this opinion, but I’m beginning to view things differently.
    I have to research more on this as it seems very interesting. One thing that is clear to me though is how everything is related together.

  14. Shiro says:

    Wow, such a good tutorial! thx for sharing. It is very detail explain the some of the basic thing!
    BTW, Happy Merdeka!!!

  15. Jaspal Singh says:

    Nice example of Ajax email signup form.
    Thanks for sharing.

  16. irengba says:

    Great one. Nicely explained.

  17. K Arun Mariappan says:

    Nice Tutorial.. Thanks you very much… :)

  18. Codeforest says:

    Great tutorial.

    Personally, I would add control on the server side if $_POST['signup-email'] is not empty before connecting to the database. Actually, db connection should be executed only if there are no errors.

    Anyway, great stuff. Thanks

  19. Chris says:

    Great tut, JSON looks sooo useful and easy. I am excited to rip into this.

  20. Daniel S says:

    Sorry, the Tut idea was nice, but it’s wrong to teach old and depricated mysql_*-Functions. You have to use PDO or mysqli. What if the User has disabled JS? There is no Fallback for non-JS-Users. Bad!

    • Author

      Thanks for the comment. These MySQL functions are not deprecated. Granted PDO or MySQLI are better tools for the job, but they would also add more complication to the tutorial. As for the no JS fallback, i opted to leave this out as the tutorial was already quite lengthy, and the focus on this tutorial was to get all these technologies to work together. Anyways, thanks for your feedback :)

  21. xvader says:

    nice tutorial. i’ll apply this to one of my site, soon :)

    thanks for sharing :)

  22. David says:

    This is an excellent article, thanks so much for sharing.

    I love seeing real life examples of technologies like this, it makes it all so much clearer and applicable.

  23. Steve Maggs says:

    An in-depth tutorial like this is really welcome. Good explanations and insight throughout the tut. I have wanted to do something with AJAX for so long but have been scared off by thinking it would take ages to get my head around it but this is ideal, a good real-world example well documented and explained….thanks!

  24. Geoffroy Bolo says:

    Hello thx for sharing, but there is a pb with the sources. Can’t download.
    Thanks to watch it.
    ++

  25. I suppose this tutorial is for begginers, but it’s very good anyway.
    There are some directions you took that I’d change a bit:
    1. instead of parseJSON you could use dataType:'json' on ajax object.
    2. instead of creating a email validator you could use filter_var.
    3. instead of creating 2 fields on the database called date and time you could create just one calleddate an then assign it as a datetime field.

    • Author

      hey thanx for your comment. i did not realize jquery could parse JSON straight from the $.ajax() just by specifying the data type. I need to read the jQuery manual more often! :) Thanks for the suggestions.

  26. Justin says:

    Nice and in depth. I liked the JSON example.

  27. Fingerlicking says:

    I just simply love (AFC) Ajax!!!

  28. Anee says:

    V nice…

  29. David says:

    I have a problem. The script works on localhost but not with my internet webhoster.
    It looks like that the E-Mail submitting works because the E-Mail is in the signups table but next to the Submit Button there is no change, there is still the “Please Wait…” text with the “loading.gif” animation Icon.

    • Author

      Hey, have you tried debugging with firebug? Firebug has a cool little net panel which lets you watch the ajax requests, what data is being sent, what data is being recieved etc.

      It sounds like you not getting a response from your server.

      • David says:

        Yes, it was my web hoster. Now the script works.
        But if the email adresse includes a minus sign (example: test@test-house.com) the error message “You have entered an invalid email address!” appears.
        Is it possible that the minus sign is accepted by the script?

      • Author

        Hey david, i think that is caused by the regular expression used to validate the email. For some reason it is not allowing hypens through. regular expressions are a right pain in the arse :)

        Tutorial City above recommended using phps built in email filter. This is a very good suggestion.

        so instead of using:

        if(empty($email)){
        $status = “error”;
        $message = “You did not enter an email address!”;
        }
        else if(!preg_match(‘/^[^\W][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\@[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\.[a-zA-Z]{2,4}$/’, $email)){ //validate email address – check if is a valid email address
        $status = “error”;
        $message = “You have entered an invalid email address!”;
        }

        replace it with:

        if(empty($email)){
        $status = “error”;
        $message = “You did not enter an email address!”;
        }
        else if(!filter_var($email,FILTER_VALIDATE_EMAIL)){
        $status = “error”;
        $message = “You have entered an invalid email address!”;
        }

    • Michael says:

      Hey David,

      Bit of a long that you’ll reply, but here goes.

      Do you know exactly what your web host changed?

      I think I have the same problem with 123Reg and I’d like to know what to ask them to change.

      Many thanks

    • twoclicks says:

      Hi David,

      i just saw your post and i have the same problem as you did. However, i was unable to submit the email to the database if i hosted it online. While in the localhost testing it works and it actually does insert the data into database, but when i upload the index.php to live server, it stucks at “please waiting…” and it doesn’t insert the data to database. I tried with Michael’s suggestion have a look with firebugs under js tabs it shows 0 request. Would you mind if i ask how did you resolve the problem?

      Cheers

  30. dr.emi says:

    nice technique!!! thanks dude..

  31. Osvaldo says:

    Hey Michael B. you has been done an excellent tutorial. Your comments and guidelines are so clear and usefull. Thanks for sharing this, it helps me to undertands more about JSON, and JQuery using AJAX.

  32. Terry says:

    Great tutorial. What if the user has javascript turned off. The next page after submission just shows a JSON object containing the key/value pairs.

    Is there a way to change this so the page redirects to the form submission page and adds a response message or alternatively takes you to a ‘thank you’ page?

    • Author

      Hey terry, i did not include any fallback in this tutorial as it was already quite lengthy, and the main principle was to get these technologies to work together. Anyhow if i was to include a fallback this is how i would do it. In the form i would have a hidden input like so:

      .

      When the page the loads use javascript to change the value of this input to 1

      $(input[name='jsenabled']).val(’1′)

      This means if js is enabled then the hidden input will have its value set to 1. If js is not enabled, then the inputs value will never be changed which means it will be set to 0. This is how we will check for JS in the php.

      so in the php i would do something like:

      if($_POST['jsenabled'] == ’1′){
      //do our ajax stuff
      }
      else {
      //js is not enabled so lets do things a little differently
      }

      This is the basics of how i would achieve a fallback. Obviously i cannot post the whole modified code, but hopefully you should get the gist from the above.

      • Author

        sorry, didnt format the html correct.

        hidden input like so:

        &ltinput type=”hidden” name=”jsenabled” value=”0″ /&gt

      • Terry says:

        Thanks again Micheal. Helped a lot and I’m testing things out further.

      • tarek says:

        I handled the degrading problem by changing the form’s action to the name of the server side file (e.g., update.php) and adding the following before the js provided in the tutorial:

        var actionBase = $(‘#newsletter-signup’).attr(‘action’); // set a variable equal to the default action of the form
        $(‘#newsletter-signup’).click(function(){
        var actionExt = ‘?action=ajaxSave’;
        $(‘.updateForm’).attr(‘action’,actionBase + actionExt); // append the appropriate parameter to the default value of the action attribute
        });

        Then, on the server side, I just check for the existence of the added parameter via

        if($_GET['action']==’ajaxSave’)

        If that doesn’t return true (signaling that javascript was disabled), then I process the submission with my non-ajaxified server side code.

  33. Corey says:

    Great tutorial, helped me get my head around JSON and using AJAX. One thing I noticed was that your use of semi colons was missing in certain places. But that’s just me nit picking :P. Again I say great Tut.

  34. chuckles says:

    Hmmmmm…….thought it would be a bit more interesting than this. Oh well Envato; you can’t win them all….:)

  35. Great tutorial. It will help me on alot of projects…

  36. tim says:

    nice work.. cheers…

  37. charles says:

    Absolutely excellent tutorial! Very straight forward and superbly explained also works perfectly! I’ve been trying to get a grasp of how ajax and php could work together and this is the perfect example. Keep doing great tutorials.

  38. Michael says:

    Is there an unsubscribe option?

    I guess I would just add 2 radio buttons for subscribe/unsubscribe and take it from there.

    Great tutorial guys!

  39. tarek says:

    Hi there…I really liked this tutorial. It gave me the know-how to start Ajaxifying several pieces of an application. However, I’ve run into one snag, which may be outside the scope of the tutorial, but I thought I’d see if anyone has any ideas.

    I’ve got this all working fine on a large form. I’m using it to INSERT as well as UPDATE a mysql DB. What’s not working are the form fields where I’m using CKEditor, a rich text editor that replaces my textareas (http://ckeditor.com/). All other fields write to the database just fine (and I don’t get any errors), but these CKEditor fields won’t write.

    Any ideas?

    Thanks in advance,
    tarek

  40. Thany says:

    How is this AJAX if you;re using JSON instead of XML?? What do you think the X stands for?

    • Author

      Just beacuse the accronym has the word XML in it, doesnt mean you have to use it. Also the request doesnt have to be asynchronous either. So i guess they really messed up there eh? :)

      Although AJAX does rely on the xhr (XMLHttpRequest object) to communicate to the server, but yet again this does not limit to only using XML (even though it has xml in its name)

  41. Sebastian says:

    Hi,
    Thanks for making AJAX user-friendly :)

    I encountered a small issue. Whenever I loaded the page I got this error message:
    “Notice: Undefined index: action in D:\www\PHP-sebi\ajax\index.php on line 2″

    So I changed the PHP so now it looks like this:
    if(isset($_GET['action'])&& $_GET['action'] == ‘signup’){…

    … and it works.

    • twoclicks says:

      Hi sebastian,

      i have encounter the same problem as you did earlier too. I modified the code according to your suggestion and that error messages has gone. However, i got another issue arise when i entered email address and click on the sign-button it shows “please wait…” forever. When i tested on local computer it actually did insert the email to the database, but when i upload the index.php to live server and performed the same action it stays at please wait …. and never insert the data to database. By any chance you know why is this happening ?

      Thank You

  42. mick says:

    Michael:

    Appreciate the tutorial. I’m just running into a slight problem. When I type in a valid email, the email goes straight to my database; however, whether I leave the field blank or type in anything in there – it always responds and remains in the “response-waiting” state.

    I copied and pasted the downloaded source onto my server, configured the database credentials and still running into the problem.

    Any sort of help would rock.

  43. Author

    Hey sorry for the late reply guys,

    anyhow have you verified that your definately getting a response from the server? if its stuck on the waiting icon, then it means its waiting for the response. If you view the net panel in firebug when making the request it will tell you the response that is returned, it indeed a response is returned.

    Let me know.

    • nicefield says:

      I’m having the same problem as these folks.

      My firebug error says:
      “responseData is null
      switch(responseData.status){ “

  44. Justin says:

    I am running into this issue as well. I would really like to see a solution, if possible.

  45. Arcturus says:

    Thanks a lot for writing this in-depth article. I learned some useful new concepts!

  46. Ricardo says:

    Not working in Chrome :( it loads another page, then echoes the comments! What to do?

  47. Matt says:

    There was so much hope in this until the last few comments, lol.

Comment Page 1 of 21 2

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.