Replacing an element and returning the new one in

2020-05-25 07:33发布

问题:

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.

回答1:

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'/>");
  });
});


回答2:

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"/>');
    });
});



回答3:

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'/>"); 

});


回答4:

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.



回答5:

Check this.

$.fn.replaceWithMod = function(obj) {
var $a = $(obj);
this.replaceWith($a);
return $a;  
};

var newObj  = $('a').replaceWithMod('<div>New Created Object</div>');
$(newObj).css('color','green');


回答6:

I wrote a little plugin to achieve a similar result because I like to be able to retrieve a pointer for the new item in one line of code.

(function($){
    $.fn['overwrite'] = function(target){
        $(target).replaceWith(this);
        return this;
    }
}(jQuery));

Usage example:

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


回答7:

If there isn't a necessity to use specifically the replaceWith method - you could use the replaceAll method which is the opposite to replaceWith.

See the answer here: (answer to a similar question asked a year later) replaceAll replaces each element in the object passed as the parameter or the elements matching the passed selector as the parameter with the matched elements and returns the matched elements (the new content).

That way, the edit in tvanfosson's answer (and the code at Keeper's answer) would look like this:

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

It's only a line shorter but for brevity and to include the option to use replaceAll() I saw fit to add this answer to this old and more-viewed question.



回答8:

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
});