Twitter bootstrap, fly out contact or feedback form with validation and Ajax submission

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):

Screen Shot 2013-05-05 at 12.16.11 PM

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 &gt; 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.

There are errors, damned errors and then there are the IE 80020101 errors.

These are the errors that follow the well laid out numerical error coding convention put in place right around the time the 2600 was the hot gaming machine. You can rest assured that somewhere in a nondescript office building someone knows the meaning of 80020101, for the seasoned programmers out there it’s almost as elusive as the hit album 0u812, remember the mystery, the assumptions, the summer of 88. If you haven’t seen it or can’t get your hands on IE8 here is what you are in for.

This error occurs in ext applications when you make an ajax request and the data that comes back is not exactly in the format that IE is looking for. In every case I have run into the code performs perfectly in Chrome and Firefox, so the development tools available in those environments will do little to help you out of this one.

As you can imagine that leaves a lot of possibilities so here are some things to look for when troubleshooting this particular error.

Are you loading external pages into your extjs panel? Not sure, take a look at your code for something like the following which is loading an external page into a panel:

Ext.getCmp('some_panel').load({
	url: '/some_external_page_with_code.cfm',
	text:'Loading...',
	scripts:true
});

In my instance, I noticed that the page in question contained a print page script that I picked from the internet that will pop up the print dialog, the code being below:

<script language=" javascript">
<!--//
  function printpage() {
  window.print();
  }
  //-->
</script> 

Now I don’t know why the

<!--//

was inserted into the script, but I do know that IE8 did not like the

<!--// 

or a coldfusion comment tag

<!---

that was further down in the page. Once these comments were removed from the page that extjs was loading the error disappeared.

Now since this error is so generic it’s very likely that this was just luck, and there are other syntax mistakes in data that’s coming into your app via ajax calls that will throw this exception. If you run down any code that causes this in addition to comments in Ajax data returns then please post them here so there will be a central point for those looking for help.

Google’s Webfonts

OK, I know most of the audience codes all day long, I can tell by the keywords that are used to find the site, and the fact the most popular articles are those that deal directly with those thorny coding problems that make the page find like finding a needle in a haystack. Recently, I decided to branch out and start an online small business inventory company and one of the first issues that I ran into was not a coding problem, it was more of a marketing problem really. The focus of intense debate revolved around ‘the look and feel’ of the application. Which brings me to fonts. I thought that I would share Google’s webfonts for those that may not know about this service.

First, for those who don’t know already, you can get an impressive array of fonts for your website served straight from Google using Google Web Fonts: http://www.google.com/webfonts.

Take a look at the image below, it shows three of the over 400 fonts available for use.

You can see the button on the right titled “Add to Collection”, the blue bar that runs across your screen will look like the following:

Now for quick use press the “Use” button and you will get a screen that contains a link to the style, you place this in between the tags of your document, for example:

<head>
<link href='http://fonts.googleapis.com/css?family=Telex' rel='stylesheet' type='text/css'>
</head>

Now all you have to do is use the style in your CSS as specified in step 4 on the same page that you got the link code from.

<p style="font-family: 'Telex', sans-serif;font-size:28px;">Just take a look at this cool font from Google</p>

Equals:

Just take a look at this cool font from Google

In case you were wondering, yes it works well with extjs.

Using the HTML canvas tag, JSON, and Javascript to capture and regenerate drawing

OK so it’s been a few weeks since the last post, but I have been busy with the holidays, this has slowed my after work development time considerably, but luckily it has not cut into my reading time and I stumbled upon Thomas Bradly’s Signature Pad JQuery plugin here http://thomasjbradley.ca/lab/signature-pad .

The plugin uses the HTML5 Canvas tag and stores the strokes in JSON format so, yes they could be placed into a database, and redrawn later (I already have some great ideas for a mind map app!) The demo is here: http://thomasjbradley.ca/lab/signature-pad-accept.

I’ll have more this week, but I just wanted to get this out there now!

A look at your most important design decision – font, and size

Let’s take a code break for a minute and discuss fonts, target audiences, and why a screen will never equal a piece of paper. When you are designing your pages, the choices that you make regarding fonts and font sizes are some of the most important. Why? First, computer screens by design are going to be harder on the eyes than paper, as paper reflects light, where computer screens emit light and are constantly being refreshed, this means that as a designer you should make every effort to ease the strain and make your site as readable as possible. Take a look at the image below:

The x-size, which is literally the size of the small x in the font family, where the point size is the distance from the top of the ascender to the bottom of the descender. This is the reason that some fonts just look bigger than others when you place them in your code using the same point size in your CSS. For a good example take a look below:

Hey I’m 12 point arial, how do I look?
Hey I’m 12 point times new roman, I know I was designed for newspapers, but how do I look on the screen?
Hey I’m 12 point veranda, how do I look on the screen?
Hey I’m 12 point tahoma, how do I look on the screen?

There you have it, not only does size matter, font style plays an equally important role, but that’s not all …

Notice that some of the fonts are Serif, with the small lines on the ends of the characters, and some are Sans Serif, without the decoration. So what does this mean to the programmer? For the web designer, it’s easier on your audience if you go with a sans-serif font style, which is the opposite of traditional printing. The reason is the dots per inch or dpi on a screen is much less than the dpi when printing, the fonts seem to scale better.