2008-04-28

A simple way to manage tab-lists, and other unique selections.

So, in the current project I'm working on, I've run into a few situations where I want to have a list of options, only one of which is allowed to be "active" at any given point in time. Examples: tabbed interfaces, editing "modes" for the shape and grid editors that I'm working on (you can be in "deleting" mode or "inserting" mode or "setting center" mode, for instance).

Basically, all I needed was to be able to say "This list of stuff is only allowed to have one thing selected at once", while showing the active selection with css.

As a first attempt, I wrote the following little bit of javascript:

function UniqueSelection(id) {
function toggle() {
UniqueSelection.active.className = "inactive";
this.className = "active";
UniqueSelection.active = this;
}

var listItems = document.getElementById(id).getElementsByTagName('li');

for(var i = 0; i < listItems.length; i++) {
listItems[i].onclick = toggle;
if(listItems[i].className == 'active'){
UniqueSelection.active = listItems[i];
}
}
}


Which works, but has one big flaw: you can only have one UniqueSelection at a time, and is a pretty ugly solution anyhow.

The following code allows you to have as many UniqueSelection elements as you want, and is shorter, clearer code:


function UniqueSelection(id) {
var listItems = document.getElementById(id).getElementsByTagName('li');

function toggle() {
for(var i = 0; i < listItems.length; i++) {
listItems[i].className = 'inactive';
}
this.className = 'active';
}

for(var i = 0; i < listItems.length; i++) {
listItems[i].onclick = toggle;
}
}


This does have some downsides - for one, it might have a visible delay on long lists. For two, you can't have multiple class names on your 'li' elements. For my purposes, this is fine - and I think that if you're using ul's in a semantic manner, it shouldn't be a problem.

The code above does show some interesting things about javascripts scoping rules though.



Update:

With a couple more lines of code, we can allow for both lists where a selection must be unique and a selection must be active, and lists where a selection must be unique, but where the current selection can be turned off without making another one:


function UniqueSelection(id, allowToggle) {
var listItems = document.getElementById(id).getElementsByTagName('li');

function choose() {
for(var i = 0; i < listItems.length; i++) {
if(listItems[i] != this)
listItems[i].className = 'inactive';
}

if(allowToggle && this.className == 'active') {
this.className = 'inactive';
}else{
this.className = 'active';
}

}

for(var i = 0; i < listItems.length; i++) {
listItems[i].onclick = choose;
}
}




Update 2: The above function clobbers the onclick attribute, and in some cases I need it to not do so. Getting it to not clobber is turning out to be frustrating though. . .


Update 3: Got it working, through a bit of education and head-banging. The new code and an explanation of what was going on deserves it's own post though. Will write it up later.

No comments:

Post a Comment