Move closing </a> tag to the end of a containing element

Viewed 1265

I'm trying to get a link to wrap around all text within a div. I can only find solutions where you move certain DOM elements entirely, or move other elements into an element.

current situation:

<div class="text">
    <a href="link">text</a> and more text
</div>

desired situation:

<div class="text">
    <a href="link">text and more text</a>
</div>

Unfortunately, I cannot change the markup, so I have to do something with jQuery.

5 Answers

Avoid messing with html directly, it's better not to change it or overwrite. All you need to do is to take next text sibling Node and append to previous a:

$('.text a').each(function() {
  $(this).append(this.nextSibling)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="text">
  <a href="link">text</a> and more text
</div>

If necessary you can check for the next node to be TextNode, if you need to skip element nodes:

if (this.nextSibling.nodeType === 3) {
  $(this).append(this.nextSibling)
}

You need to use .append( function ) to insert nextSibling of anchor into it.

$(".text a").append(function(){
  return this.nextSibling
});

$(".text a").append(function(){
  return this.nextSibling
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text">
  <a href="link">text</a> and more text
</div>

Also you can use .html( function ) instead and then remove next sibling using .remove()

$(".text a").html(function(i, h){
  return h + this.nextSibling.nodeValue;
})[0].nextSibling.remove();

Or in one line using ES6

$(".text a").html((i,h) => h+this.nextSibling.nodeValue)[0].nextSibling.remove();

$(".text a").html(function(i, h){
  return h + this.nextSibling.nodeValue;
})[0].nextSibling.remove();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text">
  <a href="link">text</a> and more text
</div>


Or using pure javascript

var ele = document.querySelector(".text a");
ele.innerHTML += ele.nextSibling.nodeValue;
ele.nextSibling.remove();

var ele = document.querySelector(".text a");
ele.innerHTML += ele.nextSibling.nodeValue;
ele.nextSibling.remove();
<div class="text">
  <a href="link">text</a> and more text
</div>

HTML/JavaScript doesn't work in a way that you can "move" a closing tag like that, but what you can do is move the text. Also, you don't need jQuery to do it; it's very easy to do with vanilla JavaScript:

let link = document.querySelector('.text a')
let textAfterLink = link.nextSibling
link.appendChild(textAfterLink)
<div class="text">
  <a href="link">text</a> and more text
</div>

You can first get the HTML inside the div with class text and then replace the closing tag </a> with '' then finally append a closing </a> tag to the replaced string so that you get what you expect:

var aHTML = $('.text').html();
aHTML = aHTML.trim().replace(/<\/a>/, '') + '</a>';
$('.text').html(aHTML);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text">
    <a href="link">text</a> and more text
 </div>

Here you have one approach that will find all unwraped text inside the element with class .text and append all of these texts to the first <a> child. This approach uses the content() method chained with a filter() using the addequated condition for remove the texts children, while at the same time they are appended to the <a> element.

$('.text').each(function()
{
    $(this).contents().filter(function()
    {
        // Filter text type only.
        return (this.nodeType === 3);
    })
    .appendTo($(this).find("a:first-child"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="text">
    <a href="link">text</a> and more text
</div>

<hr>

<div class="text">
  <a href="link">Rise up this morning</a>
  Smile with the rising sun
  <br>
  Three little birds
  <br>
  Pitched by my doorstep
  <br>
  <p>DON'T TOUCH THIS ONE!</p>
  Singing sweet songs
  <br>
  Of melodies pure and true
  <br>
  Sayin': This is my message to you
  <br>
  Saying, don't worry about a thing
  <br>
  'Cause every little thing
  <br>
  Gonna be all right
</div>

Related