Submit your widget

jQuery AJAX Validation Contact Form with Modal + Slide-in Transition

Created 13 years ago   Views 48876   downloads 10487    Author jorenrapini
jQuery AJAX Validation Contact Form with Modal + Slide-in Transition
View DemoDownload
316
Share |

Due to popular demand, here is a tutorial on how I created one of the more complicated pieces of machinery on my new site: the contact form. A lot of different techniques went into this, and I have a few people/places to thank for some of the original code that inspired my final product: primarily Design Shack for their tutorial on creating a slide-in contact form with ajax, Zachstronaut for his code on scrollable same page links (used all over my site, but most effectively on the contact link in my footer), and Yens Design for a quick how-to on creating the modal pop-up background darkening effect (surprisingly extremely easy to do with jQuery).

The HTML:

<div class="container">
  <div id="contactFormContainer">
    <div id="contactForm">
      <div class="loader">&nbsp;</div>
      <div class="bar">&nbsp;</div>
      <form name="cform" class="contactForm" action="mail.php" method="post">
        <p>Talk to me about anything. If you&rsquo;d like to work with me, or <br />
          even if you just need a hug, I&rsquo;ll get back to you shortly.</p>
        <div class="input_boxes">
          <p>
            <label for="name">Name</label>
            <span class="name-missing">Please enter your name</span><br />
            <input type="text" value="" id="name" name="name" />
          </p>
          <p>
            <label for="e-mail">E-mail</label>
            <span class="email-missing">Please enter a valid e-mail</span><br />
            <input type="text" value="" id="e-mail" name="email" />
          </p>
          <p>
            <label for="message">Message</label>
            <span class="message-missing">Say something!</span><br />
            <textarea cols="" rows="" id="message" name="message"></textarea>
          </p>
        </div>
        <input type="submit" onfocus="this.blur()" value="Submit Form" name="submit" class="submit" />
      </form>
    </div>
    <div class="contact">&nbsp;</div>
  </div>
</div>
<div id="backgroundPopup">&nbsp;</div>

 

I’m going to assume you know what you are doing with HTML. If you don’t, well then. . . this is NOT the post to start with! Moving on. . .

The PHP:

   <?php
   //declare our variables
   $name = $_POST['name'];
   $email = $_POST['email'];
   $message = nl2br($_POST['message']);
   //get todays date
   $todayis = date("l, F j, Y, g:i a") ;
   //set a title for the message
   $subject = "Message from Your Website";
   $body = "From $name, nn$message";
   $headers = 'From: '.$email.'' . "rn" .
       'Reply-To: '.$email.'' . "rn" .
       'X-Mailer: PHP/' . phpversion();
   
   //put your email address here
   mail("youremail@yourdomain.com", $subject, $body, $headers);
   ?>
   <!--Display a thankyou message in the callback -->
   <div id="mail_response">
       <h3>Thank you <?php echo $name ?>!</h3><br />
       <p>I will answer your message soon as possible.</p><br />
       <h5>Message sent on: </h5>
       <p><?php echo $todayis ?></p>
</div>   

 

Our mail.php breakdown:
  • The comments on this more or less speak for themselves. First we are getting the variables that are passed to the file from the javascript (NOT the HTML, that’s why the ID’s of the inputs don’t match up. I had to change email to e-mail so that it didn’t conflict with the comment forms on the blog posts). Also, the function nl2br() helps to replace any new lines that the user enters onto the ‘message’ textarea with line breaks so that you get a properly formatted e-mail.
  • Next, we define variables for the date, subject, body, and headers for the standard PHP mail() function.
  • After the mail() function is finished executing, you will see in our javascript that we will replace the form & loader with #mail_response so that the user gets some comfy feedback that we got their message! I see way too many folks leave out user confirmation on their contact forms, and that is just plain silly. Don’t leave your users in the dark!
  • I would also recommend putting some form of PHP spam protection in here as well. Another post, another time perhaps.

 

 

The CSS:

 
.container {
 width:960px; 
 margin:0px auto; 
 position:relative;
 }
 
/* Positions the contact form so it doesn't interfere with any other content, as well as a z-index above any other elements on the page */ 
#contactFormContainer {
 position:absolute;
 left:368px;
 z-index:12;
 }
 
/* Hides the whole contact form until needed */ 
#contactForm {
 height:289px;width:558px;
 background:#515151 url(../images/birdy.jpg) no-repeat 241px 11px; 
 border:1px solid #929191;
 display:none;
 padding:7px 12px; 
 color:#fff
 }   

/* Loading bar that will appear while the ajax magic is happening */
.bar{
 display:none; 
 background:url(../images/ajax-loader.gif) no-repeat center; 
 margin-top:100px; 
 height:40px; width:230px;
 }

/* This hides the form validation alert messages until needed */
#contactForm span { 
 display:none; 
 font-size:9px; 
 line-height:10px; 
 padding-left:6px; 
 color:#f5c478;
 }
 
/* Some styling for the contact button */
#contactFormContainer .contact {
 height:47px; width:211px;
 background:url(../images/contact_me.png); 
 position:absolute; 
 left:368px; bottom:-44px; 
 cursor:pointer;
 }
   
/* Hides the darkening layer for the Modal effect. The z-index is necessary for layering purposes, and be sure to keep the positioning/height/width the same */ 
#backgroundPopup{
 display:none; 
 position:fixed; 
 _position:absolute; 
 height:100%; width:100%; 
 top:0; left:0; 
 background:#000; 
 z-index:11;
 }     

 

I did not include the CSS styling that I used for appearances, only what was necessary to get this functional.

And our CSS rundown / explanation:
  • .container is just used for positioning everything in the middle of the page, and the position:relative property lets us absolute position the elements inside of the div.
 
#contactFormContainer {
 position:absolute;
 left:368px;
 z-index:12;
 }

 

 

  • #contactFormContainer is absolute positioning the whole contact form, this div is also necessary so that the .contact button moves with the contact form, and the z-index puts it above the darken div.
  • #contactForm Contains the form as well as all other content inside of it (loading bar, background, etc.) and is hidden until the .contact button is pressed.
  • The spans are hidden until a user tries to submit the form without properly filling out all of the fields. You will see why each one has its own class when we take a look at the scripting.

#backgroundPopup{
 display:none; 
 position:fixed; 
 _position:absolute; 
 height:100%; width:100%; 
 top:0; left:0; 
 background:#000; 
 z-index:11;
 }    

 

#backgroundPopup is placed at the bottom of the page in the HTML (it needs to be OUTSIDE of any container or else it won’t work right in IE6). This is the div that will appear and have its opacity changed when the .contact button is pressed. Make sure its z-index is above everything, but below the #contactFormContainer.

 

The [removed]

PLEASE NOTE: The following javascript is a little clunky and not very well optimized.

 

$(document).ready(function(){
 //function for contact form dropdown
 function contact() {
  if ($("#contactForm").is(":hidden")){
   $("#contactForm").slideDown("slow");
   $("#backgroundPopup").css({"opacity": "0.7"});
   $("#backgroundPopup").fadeIn("slow"); 
  }
  else{
   $("#contactForm").slideUp("slow");
   $("#backgroundPopup").fadeOut("slow");  
  }
 }
  
 //run contact form when any contact link is clicked
 $(".contact").click(function(){contact()});
 
 //animation for same page links #
 $('a[href*=#]').each(function() {
  if (location.pathname.replace(/^//,'') == this.pathname.replace(/^//,'')
  && location.hostname == this.hostname
  && this.hash.replace(/#/,'') ) {
    var $targetId = $(this.hash), $targetAnchor = $('[name=' + this.hash.slice(1) +']');
    var $target = $targetId.length ? $targetId : $targetAnchor.length ? $targetAnchor : false;
   if ($(this.hash).length) {
    $(this).click(function(event) {
     var targetOffset = $(this.hash).offset().top;
     var target = this.hash;
     event.preventDefault();      
     $('html, body').animate({scrollTop: targetOffset}, 500);
     return false;
    });
   }
  }
 });



   //submission scripts
  $('.contactForm').submit( function(){
  //statements to validate the form 
  var filter = /^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$/;
  var email = document.getElementById('e-mail');
  if (!filter.test(email.value)) {
   $('.email-missing').show();
  } else {$('.email-missing').hide();}
  if (document.cform.name.value == "") {
   $('.name-missing').show();
  } else {$('.name-missing').hide();} 
  if (document.cform.message.value == "") {
   $('.message-missing').show();
  } else {$('.message-missing').hide();}  
  if ((document.cform.name.value == "") || (!filter.test(email.value)) || (document.cform.message.value == "")){
   return false;
  } 
  
  if ((document.cform.name.value != "") && (filter.test(email.value)) && (document.cform.message.value != "")) {
   //hide the form
   $('.contactForm').hide();
  
   //show the loading bar
   $('.loader').append($('.bar'));
   $('.bar').css({display:'block'});
  
   //send the ajax request
   $.post('mail.php',{name:$('#name').val(),
         email:$('#e-mail').val(),
         message:$('#message').val()},
  
   //return the data
   function(data){
     //hide the graphic
     $('.bar').css({display:'none'});
     $('.loader').append(data);
   });
   
   //waits 2000, then closes the form and fades out
   setTimeout('$("#backgroundPopup").fadeOut("slow"); $("#contactForm").slideUp("slow")', 2000);
   
   //stay on the page
   return false;
  } 
  });
 //only need force for IE6  
 $("#backgroundPopup").css({  
  "height": document.documentElement.clientHeight 
 });  
}); 

 

Oh joy, lots and lots of javascript explainin’ to do:
  • $(document).ready(function() {}); is the necessary jQuery function required to kick off anything that runs after the page is loaded. All our code will be placed inside of this.

function contact() {
  if ($("#contactForm").is(":hidden")){
   $("#contactForm").slideDown("slow");
   $("#backgroundPopup").css({"opacity": "0.7"});
   $("#backgroundPopup").fadeIn("slow"); 
  }
  else{
   $("#contactForm").slideUp("slow");
   $("#backgroundPopup").fadeOut("slow");  
  }  

 

Here we are defining the function contact that will run each time a link with the class .contact is pressed, using jQuery’s selectors:

$(&amp;quot;.contact&amp;quot;).click(function(){contact()});

 

This allows us to give that class to any link to execute the function that opens the contact form. What this function is doing is first determining whether the form is hidden or not, and if it is then it will slide the form down, and then change the opacity of the #backgroundPopup div as well as fade it in.

$('a[href*=#]').each(function() {
  if (location.pathname.replace(/^//,'') == this.pathname.replace(/^//,'')
  && location.hostname == this.hostname
  && this.hash.replace(/#/,'') ) {
    var $targetId = $(this.hash), $targetAnchor = $('[name=' + this.hash.slice(1) +']');
    var $target = $targetId.length ? $targetId : $targetAnchor.length ? $targetAnchor : false;
   if ($(this.hash).length) {
    $(this).click(function(event) {
     var targetOffset = $(this.hash).offset().top;
     var target = this.hash;
     event.preventDefault();      
     $('html, body').animate({scrollTop: targetOffset}, 500);
     return false;
    });
   }
  }
 }); 

 

This script grabs any anchor on the page with a same page link (e.g. #something), determines the distance between it and the destination, and then creates a scrolling transition. You can edit the speed at which it transitions by changing the ‘500′ on the line $(’html, body’).animate({scrollTop: targetOffset}, 500);.

$('.contactForm').submit( function(){
var filter = /^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$/;
var email = document.getElementById('e-mail');
if (!filter.test(email.value)) {
 $('.email-missing').show();
} else {$('.email-missing').hide();}
if (document.cform.name.value == "") {
 $('.name-missing').show();
} else {$('.name-missing').hide();} 
if (document.cform.message.value == "") {
 $('.message-missing').show();
} else {$('.message-missing').hide();}  
if ((document.cform.name.value == "") || (!filter.test(email.value)) || (document.cform.message.value == "")){
 return false;
} 

 

I know there is a better way of doing this, but in the interest of time I quickly put this together. This is a nice long if statement that checks each required input field on the form to see if they are filled in properly or not. Doing it this way is definitely not a problem if you only have a couple of required fields, but if you have several than this will need to be rewritten. There are jQuery plugins out there that offer much more extensive validation functionality, but it was not necessary for what I wanted to accomplish with this simple form. If the field in question is not filled in correctly, then the corresponding error message (those spans we made earlier) is shown and return:false; stops the form from being submitted.

  
   if ((document.cform.name.value != "") && (filter.test(email.value)) && (document.cform.message.value != "")) {
 //hide the form
 $('.contactForm').hide();

 //show the loading bar
 $('.loader').append($('.bar'));
 $('.bar').css({display:'block'});

 //send the ajax request
 $.post('mail.php',{name:$('#name').val(),
       email:$('#e-mail').val(),
       message:$('#message').val()},

 //return the data
 function(data){
   //hide the graphic
   $('.bar').css({display:'none'});
   $('.loader').append(data);
 });
 
 //waits 2000, then closes the form and fades out
 setTimeout('$("#backgroundPopup").fadeOut("slow"); $("#contactForm").slideUp("slow")', 2000);
 
 //stay on the page
 return false;
} 
});

 

If all of the fields are correct, then we run the script that hides the form, shows the loading bar until the ajax variable passing to the mail.php script is complete, and then set a timer that waits ‘2000′ until it closes the whole thing.