Ok, I have taken a look at several of the contact or feedback forms on the internet in the past few weeks and they all work great, however, they require varying numbers of includes, and in some cases images, or even completely different versions of JQuery to get them up and running. The solutions that take advantage of HTML and the latest version of bootstrap.js are practically non-existent. So I thought why not roll my own then pass it on, after all it comes in at six lines of JavaScript code for the toggle (I added a form validation and ajax submit for those that need help there) , some CSS, and a good old fashioned HTML form tag. At the very least will introduce you to a few JavaScript features that you may not have been used to seeing.
Ingredients
Twitter bootstap -> http://twitter.github.io/bootstrap/index.html
Let’s start with the end first (here’s what you are getting yourself into):
I am posting the code to github as well as including it in this post, so feel free to pull it down from there and *hint* *hint* fork it and improve the validation methods if can …. as it will probably come down in a cleaner format than cut and paste would have given you.
https://github.com/jmcdonald69124/jQuery-Bootstrap-Feedback-Sliding-Form
.rotate {
/* Safari, Chrome */
-webkit-transform: rotate(-90deg);
/* Firefox */
-moz-transform: rotate(-90deg);
/* IE */
-ms-transform: rotate(-90deg);
/* Opera */
-o-transform: rotate(-90deg);
/* Older versions of IE */
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
/* CSS3 standard as defined here: http://www.w3.org/TR/css3-transforms/ */
transform: rotate(-90deg);
}
.required {
background-color:#F2DEDE !important;
border: 1px #F00 solid !important;
}
.feedback {
position : fixed; /* This will never scroll out of view */
background-color: #2F96B4;
border : 5px solid #333;
color : #FFF;
font-weight : bold;
font-size : 16px;
padding : 15px;
}
.feedback-form-wrapper {
/*
This is the CSS for the feedback div that is fixed to the top left hand side
of the screen.
*/
display : block;
z-index : 9999; /* Make sure it floats a little higher than the feedback form div below */
top : 100px;
left : -395px; /* Bring the div in and hide the left (top) border */
width : 350px;
}
/* This will put some distance between the input box and the next label */
.feedback input{
margin-bottom:5px;
}
.feedback legend{
color : #FFF;
}
.feedback-toggle {
/*
This is the CSS for the feedback div that is fixed to the top left hand side
of the screen. This div should slide with the form so that it provides a
close button when the form is slid into view.
*/
left : -49px; /* Bring the div in and hide the left (top) border */
left : -10px\9; /* Less Than IE9 Hack - Bring the div in and hide the left (top) border */
top : 200px;
cursor : pointer;
padding-left: -75px;
width : 90px; /* Since this is getting rotated width appears as height to the eye*/
height : 15px; /* Since this is getting rotated height appears as width to the eye*/
text-align : center;
border-top : 5px solid #2F96B4;
border-left : 4px solid #333;
border-right: 4px solid #333;
z-index : 10000; /* Make sure it floats above the content */
}
Of course, before I explain it would be nice to see the HTML that this code is modifying.
<!--
This is the feedback form that gets toggles in and out of view
based on the user clicking the 'feedback_toggle' div.
-->
<!-- ************************************************************** -->
<div class="feedback feedback-toggle rotate" >Feedback</div>
<div class="feedback feedback-form-wrapper">
<form id="feedback-form" class="form-horizontal">
<legend>Please give us feedback .. </legend>
<div class="alert alert-error" style="display:none">
<h4>Uh-Oh</h4>
Looks like some of the required fields are not complete!
</div>
<div class="alert alert-success" style="display:none">
<h4>Thanks!</h4>
Your feedback has been submitted, we'll get back to you as soon as we can!
</div>
<div class="alert alert-block" style="display:none">
<h4>Warning!</h4>
Something happened and the form did not get submitted...
</div>
<label>Name</label>
<input type="text" id="username" data-validation='{"required":true,"type":"text"}' name="username" class="input-block-level" >
<label>Email</label>
<input type="email" name="email" data-validation='{"required":true,"type":"email"}' class="input-block-level" >
<label>Message</label>
<textarea id="comment" name="comment" data-validation='{"required":true,"type":"text"}' class="input-block-level" style="margin-bottom:10px;" rows="4" cols="30"></textarea>
<button class="btn btn-inverse btn-large pull-right" float="right">Send</button>
</form>
</div>
<!-- ************************************************************** -->
And finally, the JavaScript that is needed to make all of this work:
// This is the Feedback toggle functionality it slides the feedback form in and out
// of view when the user clicks the div with the class .feedback-toggle
$('.feedback-toggle').click( function(){
var left = parseFloat($('.feedback')[0].style.left.match(/[0-9]+/g)) || 49,
tgl = '+=390';
(left > 49) ? tgl = '-=390' : tgl = '+=390';
$('.feedback').animate({ left: tgl}, 500);
});
/*
This is the custom validation for the feedback form
I have left the types open in the switch statement feel free
to add.
*/
validate = function(form,element){
var isValid = false, // Assume that everything starts off invalid
fields = $(form).find('[data-validation]'), //<-- Should return all input elements in that specific form.
data,
validationProps;
$.each(fields, function(index, value){
validationProps = $(value).data('validation');
if(validationProps.required){
($(value).val().length > 0 )? $(value).removeClass("required") : $(value).addClass("required");
}
if(!typeof validationProps.minlength === 'undefined' && parseFloat(validationProps.minlength) > 0){
($(value).val().length > parseFloat(validationProps.minlength))? $(value).removeClass("required") : $(value).addClass("required");
}
switch(validationProps.type)
{
case "email":
var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
//console.log(validationProps.type);
//console.log($(value).val().match(re));
($(value).val().match(re))? $(value).removeClass("required") : $(value).addClass("required");
break;
case "phone":
// add code here
break;
case "numeric":
// add code here
break;
default:
}
});
isValid = ($(form).children().is('.required'))? false : true;
(isValid)? $(form).find('.alert-error').fadeOut('fast') : $(form).find('.alert-error').fadeIn('fast') ;
return isValid;
}
// This handles the on focus and on focus lost validation
$('input,textarea').on('blur', function(){
validate($(this).parent('form'),$(this).attr('id'));
}).on('focus', function(){
$(this).removeClass("required");
});
// This is the form submission AJAX code which also
// hides the feednack form.
$("#feedback-form .btn").click(function() {
var url = "path/to/your/script.php", // the script where you handle the form input.
data = $("#feedback-form").serialize(),
isValid = validate("#feedback-form");
if(isValid){
$.ajax({
type : "POST",
url : url,
data : data , // serializes the form's elements.
success : function(data){
$('.feedback').find('.alert-error').fadeIn('fast');
$('.feedback').animate({ left: '-=390'}, 500);
},
error : function(data){
$('.feedback').find('.alert-block').fadeIn('fast');
return false;
}
});
}
return false; // avoid to execute the actual submit of the form.
});
Ok, now for the explanation, rotate is pretty simple, as it just rotates the div that will serve as the ‘tab’ for the feedback page. It’s important to wrap your head around this concept, once the div is rotated the left hand side of the div is the bottom, the right the top, and the top the left, you get the idea, so if you want to make changes to the height, as you see it, you are making changes to the width.
The CSS
The feedback class contains the background color, font color and size, and border color / size for both the tab and the main form. The feedback form wrapper class contains the code that will be applied to a div that surrounds the actual web form, this CSS will bring the feedback form above the actual page by setting the z-index to 9999, and will position the form outside of the viewable area of the page by setting the value of left to be at -395. Notice the width is 350 pixels. To give the effect of having the tab the toggle area is raised above the form wrapper with a z-index of 10000, and is given a left that positions the top of the div (remember it’s been rotated) right off of the left hand side of the screen. There is a hack here to deal with IE versions less than 9. Ok, so now our CSS is set up and everything should be positioned right when we start to place out HTML code into the page.
The HTML
Ok, the form tag uses the bootstrap CSS class form-horizontal and has the ID feed-back form, the ID will be instrumental in the operation of this widget later on when we get into the JavaScript part of the tutorial. Under the legend tag are three DIVs that contain three different messages which we will use to indicate a successful AJAX submission, an unsuccessful AJAX submission, and finally, a problem with the required input AKA a validation error. Moving on to the input and text area elements, you will notice that they all have the class input-block-level, which also comes from the bootstrap CSS and just makes the element scale to the width of the container, and gives it that cool rounded look.
One thing that may strike you is the use of the HTML5 data attribute, and the fact that is some JSON in the value, this will be used to tell the JavaScript what type of validation should be done on each of these elements. I will explain this in the JavaScript explanation section. The button has several classes applied to it, and all of them come from the bootstrap CSS. Again, it looks cool, that’s why you decided to use it, right! Anyway, this is how you get that great button in no time flat.
The JavaScript
Ok, now for the JavaScript, which will come in and do all of the heavy lifting. First, we need to be able to slide the form into the page and back out again. The trick here is that the tab needs to be attached and needs to slide in at exactly the same time as the main form. This takes only six lines of code.
<br />
$('.feedback-toggle').click( function(){<br />
var left = parseFloat($('.feedback')[0].style.left.match(/[0-9]+/g)) || 49,<br />
tgl = '+=390';<br />
(left > 49) ? tgl = '-=390' : tgl = '+=390';<br />
$('.feedback').animate({ left: tgl}, 500);<br />
});<br />
Ok, so line one we attach the function to the feedback-toggle div, nothing fancy, remember that we have the class feedback which controlled the font and background properties. Breaking these common elements out into a separate class was great in itself, but now we are going to use it to sort of tie the form to the tag by making the slide out / in code act on the feedback class. The second line gets the current value for the left hand position of the feedback DIV, the variable tgl is set by default to +=390 which will be the amount that we want to increase the CSS value of left for that DIV. The line after that contains a ternary operator which tests for left greater than 49, if that is true set tgl to -+390 otherwise, well, you know. Finally, the line $('.feedback').animate({ left: tgl}, 500); is what actually does the sliding.
Moving on we come to the custom validation part of the form, I needed to do this, because , once again, there seemed to be no good validation plugin that worked with the latest version of jQuery which is bundled with bootstrap. I plan to reuse it so it just takes the form id as a parameter, the form element is something I want to expand on in a later post. Notice the lines below:
<br />
// This handles the on focus and on focus lost validation<br />
$('input,textarea').on('blur', function(){<br />
validate($(this).parent('form'),$(this).attr('id'));<br />
}).on('focus', function(){<br />
$(this).removeClass("required");<br />
});<br />
This code attaches the validate event to all of the textareas and input elements on the page. You could easily change it to be form specific by placing a dom selector before the first section of code. Basically, this calls the validate event on focus and on lose focus of each of those elements. The form id is being passed to the function as well as the attribute id.
Once the code hits the validate function, it checks to see if there is a value in the data attribute data-validation. The code is set up to take a JSON string that contains the basic validation settings, so far, these are:
required -> true or false
minlegth -> number only
type -> email, phone, or numeric, of which only email has been coded as of yet.
Tests are made against the values in the input elements based on the settings above, and a simple true or false boolean is returned.
Finally, the code to submit the form data is fairly straightforward, first, check to see if the form is valid before submitting, then post the values to some server side script, and display the appropriate message to the user depending on what happened with the validation and submission. If all goes well hide the form by sliding it back out.
































