Code Stuff

CATCH DROP DOWN DUPLICATES

Validating forms is one of the most common uses of JavaScript. On a recent project, I had a complicated bit of form validation. The page had a bunch of drop down menus and I wanted to warn the user if they chose duplicate responses. Then I wanted to show them which menus were the offenders so they could fix it. I had some trouble with my code, but with the help of some functions found on the web I was able to adapt something that worked for me.

This example form consists of 8 drop down menus. Each menu has the same 8 choices. The user needs to make a selection in each but not duplicate their choices. If they do, we need to show them where the duplicates are.

The first code creates the form:

 1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20

<FORM name="myForm">
	<SCRIPT type="text/javascript">
		var theChoices = ['Apples','Bananas','Cabbages','Doughnuts','Eggs','Figs','Grapes','Ham'];

		for(q=1; q <= thecount; q++)
		{
			var theForm = '<select name="choice-' + q + 
				'"onchange="noDupes()"><option>Choice #' + q + '</option>';
			for(y=0; y <= thecount-1 ; y++)
			{
				theForm += '<option>' + theChoices[y] + '</option>';
			}
			theForm += '</select>';
				
			document.write('<DIV>');
			document.write(theForm);
			document.write(' <SPAN id="dupe-' + q + '"></SPAN>');
			document.write('</DIV><BR>');
		}
	</SCRIPT>
</FORM>	

Note that I've created a script here to actually create the form for me. You could just as easily hard code your form and add the necessary code to activate the upcoming function. The important parts are lines 7 and 16. In line 7 we make sure our SELECT element is named "choice-" followed by the number corresponding to its row. We also call the function "noDupes" if the user changes the menu item. In line 17 we add an empty SPAN next to our drop down menu with the id "dupe-" followed by the row number.

The next code is the script that does all the work, and it goes in the HEAD section:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

<SCRIPT type="text/javascript">

var thecount = 8;
		
function noDupes()
	{
		var all = [];
		for(k=0; k < thecount; k++)
		{
			var getSel1 = document.myForm["choice-" + (k+1)];
			var selValue1 = getSel1.options[getSel1.selectedIndex].text;
			all[k] = selValue1;
		}
	
		var isDupes = [];
		isDupes = findDuplicates(all);
		if(isDupes.length > 0) 
			{
				for(j=0; j < thecount; j++)
				{
					var getSel2 = document.myForm["choice-" + (j+1)];
					var selValue2 = getSel2.options[getSel.selectedIndex].text;
	
					var whatDupes = include(isDupes,selValue2);
					if(whatDupes == true)
					{
						document.getElementById(["dupe-" + (j+1)]).innerHTML = 
							"&larr; DUPLICATE";
					} else {
						document.getElementById(["dupe-" + (j+1)]).innerHTML = "";
					}
				}
			} else {
				for(h=0; h < thecount; h++)
				{
					document.getElementById(["dupe-" + (h+1)]).innerHTML = "";
				}
			}
		}

function findDuplicates(arr) 
	{
		var len=arr.length,
		out=[],
		counts={};

		for (var i=0;i<len;i++) 
		{
			var item = arr[i];
			var count = counts[item];
			counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
		}

		for (var item in counts)
		{
			if(counts[item] > 1)
			out.push(item);
		}

		return out;
	}

function include(arr, obj) 
	{
		for(var i=0; i<arr.length; i++) 
		{
			if (arr[i] == obj) return true;
		}
	}

</SCRIPT>

Change line 3 to the number of options in your list. The "noDupes" function is fired whenever the user changes a drop down menu. It creates an array of all the current selections. It then checks for duplicates in the array. If there are no duplicates, we're done. If there are duplicates it creates another array with the names of the duplicates. We then loop back through the user choices. If the current selections match a name in the duplicates array we mark them.

If you use the VALUE attribute for your form options, you'll want to change lines 11 and 22 to find the "value" not the "text".

The function I named "findDuplicates" was created by someone else and found on the web. Unfortunately I didn't save the source, but a quick search revealed several sites using it as an example. "findDuplicates" compares two arrays and returns an array with any duplicates found.