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:
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.
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; }
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:
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
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:
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:
- Make sure the user actually submitted an email address
- Make sure the email address submitted is a valid email address
- 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.