tags:

views:

3661

answers:

5

Hi,

How do you replace an element in jQuery and have the replacement element returned instead of the element that was removed?

I have the following scenario. I have many checkboxes and once you click one of them, that checkbox is replaced by a loading icon. Once some AJAX stuff happens, the loading icon is replaced by a tick icon.

Using jQuery's replaceWith, you'd do something like:

$("input[type='checkbox']").click(function() {

  $(this).replaceWith("<img src='loading.jpg' alt='loading'/>");
  $.post("somepage.php");
  $(this).replaceWith("<img src='tick.jpg' alt='done'/>"); 

});

However, this doesn't work because replaceWith returns the element that was removed, not the one which was added. So after the AJAX stuff completes, loading.jpg will just stay there forever.

Is there some way I can return the replacement element without selecting it?

Thanks in advance.

+2  A: 

You could give it a unique id using the index:

$("input[type='checkbox']").click(function() {
  var index = $("input[type='checkbox']").index(this);
  $(this).replaceWith("<img src='loading.jpg' id='myLoadingImage" + index + "' alt='loading'/>");
  $.post("somepage.php");
  $('#myLoadingImage'+index).replaceWith("<img src='tick.jpg' alt='done'/>"); 

});
Jose Basilio
Sorry, I should have been clearer. I have many of these checkboxes, so I can't rely on ids.
Philip Morton
I updated the code. Now it gets a unique id using the index of the checkbox.
Jose Basilio
Although faster than tvanfosson's, it's still a wasteful search, take a look at Keeper's answer.
cdmckay
+6  A: 

Give the loading image a class, then in the post callback, use the class as a selector to find the image you've just injected.

$("input[type='checkbox']").click(function() {
  $(this).replaceWith("<img src='loading.jpg' alt='loading' class='loading-image' />");
  $.post("somepage.php", function() {
      $('.loading-image').replaceWith("<img src='tick.jpg' alt='done'/>");
  });
});

If you may have several of these running at a time, you can get the closest parent of this and use that as the context when searching for the class.

EDIT: Another alternative that uses a variable to store the new element and removes the need to apply the class and search for the new element when the function returns.

$("input[type='checkbox']").click(function() {
  var loading = $("<img src='loading.jpg' alt='loading' />");
  $(this).replaceWith(loading);
  $.post("somepage.php", function() {
      loading.replaceWith("<img src='tick.jpg' alt='done'/>");
  });
});
tvanfosson
Instead of using a .loading-image class, couldn't you just keep the reference to the loading img and put that in the callback, instead re-finding it with $('.loading-image')?
cdmckay
The question (and answer) was specific to replaceWith which returns the element that was removed, not the element that was created. You could create the element and store a reference to it in a variable, then do the replacement. In that case, I think yes you could use the reference and not look it up again.
tvanfosson
+9  A: 

Create an element and use it as parameter to replaceWith:


$('input[type=checkbox]').click(function() {
    var img = document.createElement('img');
    img.src = 'loading.jpg';
    $(this).replaceWith(img);
    $.post('somepage.php', function() {
        $(img).replaceWith('<img src="tick.jpg" alt="done"/>');
    });
});

Keeper
This actually works +1
Jose Basilio
I like this, no cluttering with additional classes or ids, you know exactly which img to replace. Very clean.
Mario Menger
+1 Didn't see this until I had updated my answer with similar code. I'd still use jQuery though to create the new element.
tvanfosson
A: 

Why not make an intermediate jquery object, like this?...

$("input[type='checkbox']").click(function() {
    var insertedElement = $("<img src='loading.jpg' alt='loading'/>");
    $(this).replaceWith(insertedElement);
    $.post("somepage.php");
    var anotherInsertedElement = $("<img src='tick.jpg' alt='done'/>");
    $(this).replaceWith(anotherInsertedElement);
    //do something with either of the inserted elements
});
belugabob
You have syntax errors in this code
Jose Basilio
Additionally, the reference to the original checkbox $(this) is lost once the the replaceWith method is called, so even after fixing the syntax errors, it doesn't work.
Jose Basilio
Also, $.post is asynchronous.
cdmckay
OK - I corrected the typo.HAving seen the post by tvanfosson, and re-read the original post, I now understand the intent of the original code and agree with your comments.
belugabob
A: 

The reason your code doesn't work is that the first replaceWith replaces the item that this refers to. The second replaceWith attempts to replace it again, but since it is already gone, there is nothing to replace. And the tick icon won't get shown.

Your best bet is to use the post callback function that tvanfosson suggests.

Mario Menger