javascript - Prototype JS - Moving elements between two containers - what's wrong here? - Stack Overflow

I'm trying to move elements between two lists. Elements when clicked should move to the other list

I'm trying to move elements between two lists. Elements when clicked should move to the other list. Prototype JS code:

document.observe('dom:loaded', function() {

  $$('li.available-item').each(function(element){
    element.observe('click', function(){
      element.removeClassName('available-item');
      element.addClassName('selected-item');
      $('selected-list').insert(element);
    });
  });

  $$('li.selected-item').each(function(element){
    element.observe('click', function(){
      element.removeClassName('selected-item');
      element.addClassName('available-item');
      $('available-list').insert(element);
    });
  });

});

Sample elements:

<ul id="available-list">
  <li class="available-item">Apple</li>
  <li class="available-item">Orange</li>
  <li class="available-item">Grapes</li>
</ul>

<ul id="selected-list">
  <li class="selected-item">Pineapple</li>
  <li class="selected-item">Papaya</li>
</ul>

While it's working the first time I'm clicking on the elements, once an element moves to the other list they don't move to the other (original) list when clicked.

What am I doing wrong here?

I'm trying to move elements between two lists. Elements when clicked should move to the other list. Prototype JS code:

document.observe('dom:loaded', function() {

  $$('li.available-item').each(function(element){
    element.observe('click', function(){
      element.removeClassName('available-item');
      element.addClassName('selected-item');
      $('selected-list').insert(element);
    });
  });

  $$('li.selected-item').each(function(element){
    element.observe('click', function(){
      element.removeClassName('selected-item');
      element.addClassName('available-item');
      $('available-list').insert(element);
    });
  });

});

Sample elements:

<ul id="available-list">
  <li class="available-item">Apple</li>
  <li class="available-item">Orange</li>
  <li class="available-item">Grapes</li>
</ul>

<ul id="selected-list">
  <li class="selected-item">Pineapple</li>
  <li class="selected-item">Papaya</li>
</ul>

While it's working the first time I'm clicking on the elements, once an element moves to the other list they don't move to the other (original) list when clicked.

What am I doing wrong here?

Share Improve this question edited Dec 27, 2011 at 17:57 Rob W 349k87 gold badges807 silver badges682 bronze badges asked Mar 11, 2010 at 10:29 user291377user291377 1
  • I replied to your follow-up question below (you won't get notification of my doing so there, hence telling you here). – T.J. Crowder Commented Mar 11, 2010 at 14:38
Add a ment  | 

1 Answer 1

Reset to default 6

The reason is that when you move an item, it's still got the old event handler attached that will just move it again.

This is a classic place for using event delegation. Instead of watching for clicks on the elements, look for clicks on the lists (since clicks bubble up) and then move the relevant element. Something like this:

$('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 converse for selected-list.

You could even use just one handler for both lists:

$('available-list').observe('click', listClick);
$('selected-list').observe('click', listClick);

function listClick(event) {
    var fromType, toType, li;

    // Get the clicked list item
    li = event.findElement('li');
    if (li) {
        // We're handling it
        event.stop();

        // Determine whether moving to the selected or available list
        if (this.id.startsWith("selected")) {
            fromType = "selected";
            totype   = "available";
        }
        else {
            fromType = "available";
            totype   = "selected";
        }

        // Update class names
        li.addClassName(toType + '-item').removeClassName(fromType + '-item');
        $(toType + '-list').insert(li);
    }
});

It gets even simpler if you ditch the classes on the items (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);
    }
});

Somewhat OT, but you may not need those selected-item and available-item classes at all. With the above, you don't need them to find them anymore, and in your CSS, you can use descendant selectors for styling the elements:

#selected-list li {
    /* ...styles for the `li` elements in the `selected-list` ... */
}
#available-list li {
    /* ...styles for the `li` elements in the `available-list` ... */
}

If you only want to affect lis that are direct children of the lists, use child selectors instead of descendant selectors (note the >):

#selected-list > li {
    /* ...styles for the `li` elements in the `selected-list` ... */
}
#available-list > li {
    /* ...styles for the `li` elements in the `available-list` ... */
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745003062a4605615.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信