Cascading form require/validation

I ran into an interesting problem recently dealing with some complicated form validation. The issue was that we had several forms with fields that were required or optional based on if other inputs were filled out, with the requirements falling in a specific order. I came up with an interesting solution that looks at a data-ignore-validation attribute on the current form element and, if it exists will check the form element(s) with that name to see if they are filled out, or if they have a similar data-ignore-validation attribute meaning they can possibly be ignored as well. We have a nice little recursive solution that will check all of the form elements in a chain to see if the current one can be ignored.

All we need to do is send the following function the form element to be checked as well as our form, and it will tell us if the element passed in should be ignored.

	function ignoreField(elem, form) {
		//if we have an data-ignore-validation property, we can ignore _this_ .val() if the field with the name = ignore-validation has a .val() set
		var ignoreOn = $(elem).data('ignoreValidation');
		if(ignoreOn) {
			ignoreOn = ignoreOn.split(',');
			//We use this var to hold the complete list of for elements we need to check
			var $ignoreFields = $();

			//get all of the fields this one can be ignored on
			for(var i = 0; i < ignoreOn.length; i++) {			
				$ignoreFields = $ignoreFields.add(form.find('input[name="'+ignoreOn[i]+'"], select[name="'+ignoreOn[i]+'"]'));
			}

			//(recursively) check if any of the fields in the ignoreValidation have a value set
			for(var i = 0; i < $ignoreFields.length; i++) {
				if($ignoreFields.val()) {
					return true;
				}
				return ignoreField($ignoreFields.eq(i), form);
			}
		}		
		return false;
	}

Of course we do have an issue here where an inexperienced developer could put in a circular reference and we would end up with and infinite loop, but I leave it to you to either fix that issue, or just be smart enough not to do that.

Posted in javascript, jQuery, programming | 2 Comments

I’m pretty sure I am not the only geek in this town.

Font graffiti found in the men's bathroom @ The Vault bar, Asheville, NC

So, I am not really a font geek (other than the usual hatred for Comic Sans), but apparently there are a few in my town. I found this on the wall of the men’s bathroom at The Vault in download Asheville, NC. I think it is fair to assume that there are a few other geeks in your town when this is the kind of graffiti found on the walls of a bar.

Posted in Asheville, Geeks, NC, pics | Leave a comment

Duplicate IDs are baaaaaaaaaaaaaaad

If you are not already very aware, duplicate IDs in your markup are a very bad thing. Now, technically they will work fine in CSS, and can possibly even make it faster, BUT they WILL break your javascript. Basically when you have multiple elements with the same ID what the browser will do is unpredictable.

Sometimes in some browsers you might get what you want, other times in other browsers the wrong thing will happen, sometimes nothing will happen. You never know. On many different occasions I have been helping someone with some javascript, or fixing a website for a job and things just won’t work, and eventually I find the problem to be duplicate IDs. Dealing with this problem again today, I wrote a little jQuery plugin that checks your page for duplicate IDs. It is pretty simple, and you should never actually have this on a production site, it is just something you run while you are developing so you can yell at the jackass who wrote crappy markup to make sure you aren’t doing things you shouldn’t. The full code for the plugin is this:

(function($) {
	$.dupCheck = function() {
		var ids = [], dups = [], dupCount = 0;

		//this just displays the result if there is no console
		if (!window.console) {
			var console = {
				log: function(msg) {
					$('body').append(msg);
				}
			};
		} else {
			console = window.console;
		}		
		
		$('*').each(function() {
			var id = this.id, i = 0, len = ids.length, isDup = false;
					
			if(id) {
				for(i=0 ; i < len ; i++) { //loop over the IDs we have already processed to see if the current one is a dup
					if(!isDup && id === ids[i]) { //if the ID is a dup, add it to the dups list and set our bool				
						if(checkIfAlreadyDup(id) === false) {
							dups.push(id);						
						}
						isDup = true;
						dupCount++;
						break;
					}
				}
				
				if(!isDup) { //if the ID was not a dup, add it to the list of processed IDs
					ids.push(id);
				} else {	//if the ID was not a dup, clear out our bool
					isDup = false;
				}
			}
		});
		
		if(dups.length === 0) {
			console.log('No duplicate IDs found =)');
		} else {
			console.log('' + dups.length + ' duplicate IDs found repeated ' + dupCount + ' times =(');
		}
		
		function checkIfAlreadyDup(id) {
			var len = dups.length, i = 0;
			for(i = 0; i < len; i++) {
				if(dups[i] === id) {
					return true;
				}
			}
			return false;
		}		
		
		return dups;
	}
})(jQuery);

The way to use this is to load the plugin (or even just paste the code into your javascript console) then run the function:

	var dups = $.dupCheck();

You obviously need to do this after the document is ready, and after any offending javascript/ajax calls have completed.

It will output a message telling you how may duplicate IDs you have, and it returns an array of the IDs that are duplicates. It is pretty simple, but if you are banging you head against the wall trying to figure out why your javascript is not working, just run it, and it might give you the answer.

Download: Dupcheck.js

And I have now run this on this page, apparently I have a duplicate ID! Maybe I need to just get rid of that facebook ‘like’ button.

Posted in javascript, jQuery, programming | 4 Comments

Updates to my pub/sub

I have updated my pub/sub plugin.  The two changes are:

It now uses the full words, publish, subscribe, and unsubscribe – this change was because with 1.5, jQuery now has a sub method which I do not want to overwrite.

Also, you can now publish and subscribe multiple tags at once using a space separated list like so:


$.publish('first/tag second/tag');

$.subscribe('first/tag second/tag', function(){/*do something*/});

This just make it more like the rest of jQuery events and such.

The new version can be downloaded here:

Live DOM sub/pub

Posted in javascript, jQuery, programming | Leave a comment

Got to hang out at Google for dayofjs

I got to go to the dayofjs conference (thanks MJG!) Not only was the conference really interesting, but I also got to hang out at Google which was cool. So, I snapped a few pics, as one does.

This is where I found out that I parked about as far as I could have from where I wanted to be.

Google lunch.

Can’t really complain about the day

Ahh, the free beverage fridge

This doesn’t have anything to do with Google or Dayofjs, but I got In-and-Out on my way home after being stuck in traffic for 2 hours, because it has been a long time since I have had it.


The mobile talks of the day were about:

Sencha Touch: http://www.sencha.com/products/touch/

Appcelerator’s Titanium: http://www.appcelerator.com/

jQuery Mobile: http://jquerymobile.com/

There was also a fair amount of talk about PhoneGap: http://www.phonegap.com/

Yehuda Katz also gave a talk about Sproutcore that was really good.  It was not really a mobile talk, but it was still very informative and interesting.

Posted in javascript, jQuery, programming | 2 Comments

Unit testing jQuery w/ QUnit

So, like most developers I love having unit test, but I hate writing them. Really figuring out the best way to write them and have them work well, is a pain in the ass, and that is what I hate. I have spent some time recently playing with QUnit and despite the number fact that I have found a number of posts online about it, none of them have provided (in my mind) a good way to test a site. The ideas used work well for testing a library, or specific functions, but I don’t write libraries or one off functions, I develop websites. So, I have come up with a method that I like that allows me to test my sites in a way that I like.

The Problems:

The unit testing information I have found mainly deals with testing libraries – this is no good for me.
Testing involves putting QUnit on your page, along with its specific markup – although you can have a “debug” mode for this, it just seems like a bad idea, for a number of reasons, including it not really being an accurate representation of your page, and it does not work across page requests.
Using headless testing – it is cool, but not cross browser or even really O/S ready.
Using something like Selenium – also cool, but involves building tests using a new tool that uses java.

My solution:

I have come up with my own solution, which, I admit is not perfect, but it does a darn good job of testing what I need tested. Basically it involves having a very simply html page next to your site, that loads your site in an iframe and runs the tests on it. It is cross-browser and cross-O/S safe, it works for pretty much any site, and uses the same javascript/jQuery I already write every day.

There are a couple of problems still with my solution, but they are pretty easy to overcome, and writing tests becomes very simple. The basic page we need to get started with the testing is this:

<html>
<head>
<title>QUnit tester</title>
<link type="text/css" href="/js/qUnit/qunit.css" rel="stylesheet" />
<script src="/js/qUnit/qunit.js" type="text/javascript"></script>
<script src="/js/jquery-1.4.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
//set jquery to no conflict, so we do not have a problem with the version from in the page
var $$ = jQuery.noConflict(true);
var $ = jQuery = null; //we will be using the normal jquery vars soon enough
</script>

</head>
<body>

<div>
<h1>QUnit Tests</h1>

<div style="float: left">
<iframe height="700" width="1000" id="myFrame"></iframe>
</div>

<div style="float: right">
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup, will be hidden</div>

<input type="submit" value="Start Tests" id="startTests" />
</div>
</div>
</body>

<script type="text/javascript">
var pageNumber = 0;
$$('#myFrame').load(function () {
	//grab jQuery from inside the document
	$ = jQuery = window.frames[0].jQuery;

	//turn off async so tests will wait for ajax results
	$.ajaxSetup({ async: false });

	//turn off animations so they do no beark tests
	$.fx.off = true;

	//increase our page counter
	pageNumber++;

	//if we are not on the first page, find what tests to run
	if(pageNumber > 1) {

	switch(pageNumber) {
		case 2:
		page2tests();
		break;
		case 3:
		page3tests();
		break;
	}

	} else {
		//else, start the tests when they hit the run button
		$$('#startTests').click(function (e) {
			page1tests();
			return false;
		});
	}
});

function page1tests() {
module("Page 1 tests");

	test('Make sure thingy shows and hides - when we click button', function() {
		ok($('#thingy').is(':visible'), 'Thingy starts visible');

		$('#thingyButton').click();

		ok(!$('#thingy').is(':visible'), 'Thingy hidden after click');

		$('#thingyButton').click();

		ok($('#thingy').is(':visible'), 'Thingy visible again after second click');

		//go to page 2
		$$('#myFrame').attr('src', location.protocol + '//' + location.hostname + '/examples/qunit/page2.html');
	});
}

function page2tests() {
	module("Page 2 tests");

	test('Make sure ajax call works - when we click button', function() {
		ok($('#thingy').text() === 'Ajax response goes here', 'Text correct before ajax call');

		$('#ajaxButton').click();

		ok($('#thingy').text() === 'It worked!', 'Text correct after ajax call');

		//go to page 3
		$$('#myFrame').attr('src', location.protocol + '//' + location.hostname + '/examples/qunit/page3.html');
	});
}

function page3tests() {
	module("Page 3 tests");

	test('Make sure dialog comes up - when we click button', function() {

		ok(!$('#myDialog').is(':visible'), 'Dialog starts hidden');

		$('#dialogButton').click();

		ok(!$('#myDialog').is(':visible'), 'Dialog starts hidden');
	});
}

//load up a SOP friendly URL
$$('#myFrame').attr('src', location.protocol + '//' + location.hostname + '/examples/qunit/page1.html');

</script>

</html>

Note: We can (and probably should) actually move our tests into different .js files making it much easier to deal with as our number of tests grow.

We are doing a couple of interesting things here, first we are testing multiple pages at one time. Every time a new page loads up, we grab the jQuery refrence from inside of it, then run the tests that are specified for that page.

Another cool thing is how we get the jQuery reference for each page.

We start by loading jQuery using noConflict(true)

This is because we need to grab the jQuery instance from inside the actual website. When jQuery attaches events to DOM elements, it actually saves those events inside of itself, so although we can trigger events inside of the page itself using our external jQuery, triggering events inside of the iframe will not actually fire any events that were created inside the page. So, instead we grab the jQuery that is actually on the page and trigger the events using it. This has the added bonus that because it is the reference from inside the page we are loading, we can reference DOM nodes as though we were working that that page directly.

Here we grab the jQuery reference from inside the iframe with:

	$ = window.frames[0].jQuery;

Note: For ANY of this to work we must adhere to SOP, this is why we load this up on a server, side by side with our site. This is why I am loading up the iframe using location.protocol + ‘//’ + location.hostname rather than typing out the URL. This will allow it to work as we move between servers and such.

One of the cool things we are doing here is tying the starting of the tests to a button, so we can get the page to any state necessary before starting the tests – such as logging in, waiting for ajax requests to finish, or navigating to somewhere specific (not that we couldn’t do these in the tests, it just gives us options.)
Also, before we run our tests we are running the 2 following commands:

	$.ajax({async: false});
	$.fx.off = true;

This will make our ajax requests and animations synchronous. Although you would never do this (especially the ajax one) on a site, for our tests it is necessary to ensure that the page is ready before we perform each test.

Now that we have done this we can run our test just like we were on the page directly.

We can select elements and trigger events on them, like so:

	$(elem).click(); or $(elem).trigger(‘click’);
	$(elem).mousedown(); or $(elem).trigger(‘mousedown);
	Test things, such as visibility:
	$(elem).is(‘:visible’);

Basically anything you would normally do. Simple and easy.

This is not a perfect way to test your events, it is however pretty good, and will let us know when we break things.

Here are some examples of tests in action. I hope this helps you get started with unit testing.

Tests in action!

Posted in javascript, jQuery, jQueryUI, programming, qUnit, Unit Testing | 4 Comments

Playing with CSS hooks

So, I wanted to give the new CSS hooks in jQuery a try. Unfortunately, the usually well documented jQuery has this as the total documentation on the hooks:

As of version 1.4.3, jQuery’s CSS module was rewritten to provide a set of “hooks” for the .css() method. This advanced feature, $.cssHooks, allows for fine-grained control over the way jQuery handles certain style properties and enables the creation of custom, browser-normalized properties. The $.cssHooks object also extends the set of properties available to the .animate() method.

Which isn’t much to go on. So, I broke out the old source code to see whats up. Basically, you can hook into a CSS property and create setters and getters for it. I started by making a simple hook that allows you to use show and hide on the display property, and have it call show() and hide(). The code is pretty simple:

jQuery.cssHooks.display = {
	set: function(elem, value) {
		if (typeof (value) === 'string') {
			if (value === 'hide') {
				$(elem).hide();
			} else if (value === 'show') {
				$(elem).show();
			} else {
				elem.style['display'] = value;
			}
		} else {
			if (value.hide) {
				$(elem).hide(value.hide);
			} else if (value.show) {
				$(elem).show(value.show);
			} else {
				elem.style['display'] = value;
			}			
		}
	}
};

This simply checks if you are passing in a string or an object, and then calls show/hide with the supplied value (in the case of an object.) If you are not using show/hide it runs node.style[‘display’] = value; which is what normally happens when you call .css.

I made an example for it here:

I’m a thing!




The code here is pretty simple too:

$('#hookButton').click(function(e) {
	var $this = $(this);
	if($this.text() === 'Hide') {
		$('#cssHookTest').css('display', 'hide');
		$this.text('Show');
	} else {
		$('#cssHookTest').css('display', 'show');
		$this.text('Hide');		
	}
});

$('#hookButton2').click(function(e) {
	var $this = $(this);
	if($this.text() === 'Hide Slow') {
		$('#cssHookTest').css('display', {'hide': 'slow'});
		$this.text('Show Slow');
	} else {
		$('#cssHookTest').css('display', {'show': 'slow'});
		$this.text('Hide Slow');		
	}
});	

$('#hookButton3').click(function(e) {
	var $this = $(this);
	if($this.text() === 'Hide REALLY Slow') {
		$('#cssHookTest').css('display', {'hide': 1400});
		$this.text('Show REALLY Slow');
	} else {
		$('#cssHookTest').css('display', {'show': 1400});
		$this.text('Hide REALLY Slow');		
	}
});		

$('#hookButton4').click(function(e) {
	var $this = $(this);
	if($this.text() === 'Hide Normal') {
		$('#cssHookTest').css('display', 'none');
		$this.text('Show Slow');
	} else {
		$('#cssHookTest').css('display', 'block');
		$this.text('Hide Normal');		
	}
});	

So, that’s about it, the CSS hooks, although called an advanced feature are really not that hard to use. So, give ’em a try.

Posted in javascript, jQuery, programming | Leave a comment

jQuery Live DOM sub/pub plugin

Updated 2/10/10 – for the updates to the plugin (See: here)

I made a new jQuery plugin the other day, it is pretty simple, it expands on the idea subscribe/publish idea. Basically it allows you to bind subscriptions to DOM nodes.

You use it like this:


//subscribe a node
$(selector).subscribe(
	'subscription/name',
	function(subName, [arg1], [arg2],...)
	{/*do something*/}
);

//publish
$.publish(
	'subscription/name', [arg1], [arg2],...
);

The idea is that you are probably using sub/pub to keep your DOM interaction separate from your non DOM related javascript. So, when you publish, there is a good chance that the subscriber will take the published information and do something to the DOM based on it. Inside of you sub callback, this is the DOM node following jQuerys normal pattern for this.

You can still setup normal subscriptions like so:

$.subscribe(
	'subscription/name',
	function(subName, [arg1], [arg2],...)
	{/*do something*/}
);

One thing to note is that nothing is actually bound to the nodes. In reality the selector that you give is simply saved, and used again when you publish, so this works like .live in that it will even work on nodes added to the DOM after you subscribe. Also like .live though, you must provide the full selector as a string, and you can’t use any of the traversal methods to select your nodes.

    Demo:

You must enter something here

Watch me.

The code for this is :

$('#formId').submit(function(e){
	validateForm();
	return false;
});

$('#response').subscribe('formValidateDone', function(subName, result) {
	if(result) {
		$(this).html('The form is valid!');
	} else {
		$(this).html('Please try again!');
	}
});

function validateForm() {
	$.publish('formValidateDone', $('#textInput').val() !== '');
}

Plugin Link: Plugin page

Download: Download

Posted in javascript, jQuery, programming | Leave a comment