views:

62

answers:

4

I have two divs, one that holds some stuff and the other with all possible stuff. Clicking on one of the divs will transfer items to the other div. The code I came up with is:

$("#holder > *").each(function() {
    $(this).click(function(e) {
        $(this).remove();
        $("#bucket").append(this);
    });
});

$("#bucket > *").each(function() {
    $(this).click(function(e) {
        $(this).remove();
        $("#holder").append(this);
        });
});

This one works perfectly, except that the event handlers need to be refreshed once I append or remove elements. What I mean is, if I first click on an element, it gets added to the other div, but if I click on this element again, nothing happens. I can do this manually but is there a better way to achieve this?

+5  A: 

Try jquery live events .. the $.live(eventname, function) will bind to any current elements that match as well as elements added to the Dom in the future by javascript manipulation.

example:

$("#holder > *").live("click", function(e) { 
        $(this).remove(); 
        $("#bucket").append(this); 
}); 

$("#bucket > *").live("click", function(e) { 
        $(this).remove(); 
        $("#holder").append(this); 
});
John Hartsock
@John: Thanks for the reply. I am not sure if I am missing but when I replace my code with this, nothing happens. I am using jQuery-1.4.2. Am I missing out on something? I mean, even the initial events are not working.
Legend
This won't work. `jQuery.fn.live` needs a selector to work with... it can't work with `$(this)`...
J-P
I guess so. I knew "this" is messing up things.
Legend
@Legend, pls see my answer.
J-P
ok I have corrected the solution to properly worksorry about that
John Hartsock
Ok. I guess, instead of `$("#holder > *").each`, just removing that line and substituting `$(this)` with `$("#holder > *")` in the second line does the trick. Thanks John and J-P.
Legend
yep no problem, glad to help out
John Hartsock
+1  A: 

Have you looked at jQuery's live function?

Marek Karbarz
@Marek: Thanks for the pointers. Currently looking at it.
Legend
A: 

Using .live( 'click', function() { will work with all future items

Dan Heberden
Actually, it won't. Unless you mean to unbind / rebind when elements are added to the DOM. I think you mean to say .live('click', function(){
Dan Esparza
My understanding was that bind doesn't work with future items but only with elements that currently match a given selector [quote from `live` documentation in jQuery): "This new element also matches the selector .clickme, but since it was added after the call to .bind(), clicks on it will do nothing."
Marek Karbarz
I did mean .live, sry for the confusion - i was picking up my girlfriend and was in a hurry typing it in on my phone and typed bind out of habbit, lol
Dan Heberden
+3  A: 

Here you go, using the more intuitive delegate API:

var holder = $('#holder'),
    bucket = $('#bucket');

holder.delegate('*', 'click', function(e) {
    $(this).remove();
    bucket.append(this);
});

bucket.delegate('*', 'click', function(e) {
    $(this).remove();
    holder.append(this);
});
J-P
@J-P: Ahh... Just accepted John's solution. +1 for the help. Just as a matter of curiosity, is there any advantage using delegate over live?
Legend
@Legend, Yes, it's faster, because it doesn't require you to redundantly select `#header > *` and `#bucket > *` first.
J-P
@J-P: Makes sense. Thanks for the explanation.
Legend
`.delegate()` is indeed faster here, just a habit for jQuery 1.3ers to think of `.live()` first (or even the `.livequery()` plugin if from earlier days)
mVChr