The reason is that when you move an element, it still gets the attached old event handler, which will just move it again.
This is the classic place to use event delegation. Instead of tracking clicks on items, find the clicks on the lists (because the clicks are bubbling), and then move the corresponding item. Something like that:
$('available-list').observe('click', function(event) { var li; li = event.findElement('li'); if (li) { event.stop(); li.addClassName('selected-item').removeClassName('available-item'); $('selected-list').insert(li); } });
... and the opposite for selected-list .
You can use only one handler for both lists:
$('available-list').observe('click', listClick); $('selected-list').observe('click', listClick); function listClick(event) { var fromType, toType, li;
It becomes even easier if you throw classes on the elements (see below):
$('available-list').observe('click', listClick); $('selected-list').observe('click', listClick); function listClick(event) { var targetList, li; // Get the clicked list item li = event.findElement('li'); if (li) { event.stop(); targetList = this.id.startsWith("selected") ? "available-list" : "selected-list"; $(targetList).insert(li); } });
Partly OT, but you may not need these selected-item and available-item classes. You donβt need them to find them anymore, and in your CSS you can use the descendant selector to style the elements:
#selected-list li { } #available-list li { }
If you want to affect only li , which are direct children of lists, use the child selector instead of the child selectors (note > ):
#selected-list > li { } #available-list > li { }