Replace/change text of a button but leave inner html elements

Given a button with an icon:

<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
  People <span class="caret"></span>
</button>

I want to replace the text People and leave the html part of the button.

I have a situation that may require some flexibility. I may not know the inner html of the button.

The resulting html would be something like:

<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
  Jeff <span class="caret"></span>
</button>

I do happen to be using jQuery and if I do:

$('button.dropdown-toggle').text('Jeff');

Obviously that will remove the caret. I don’t want to remove the caret.

I know that I can get the caret by doing .children(). But I won’t necessarily know what order the html element would be in. Maybe the caret is first, or maybe it was placed after the text, it could be in any order. What if there are two icons? I want to only replace the text of the button and leave the html.

I don’t usually have control of the HTML that will be in the button.


solution

You may not need jQuery for this.

If the position of the text node is known, you can just access the .caret element’s previous sibling text node and change the value directly:

document.querySelector('.btn .caret').previousSibling.nodeValue = 'Something';
.caret {
  display: inline-block; width: 0; height: 0; margin-left: 2px; vertical-align: middle; border-top: 4px dashed; border-top: 4px solid\9; border-right: 4px solid transparent; border-left: 4px solid transparent;
}
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
  People <span class="caret"></span>
</button>

Alternatively, if the position of the text varies, you could also just use the .content() method to retrieve the children elements and text nodes. Iterate over the values and determine if it is a text node and change it.

$('.btn').contents().each(function() {
  if (this.nodeType === 3 && this.nodeValue.trim()) {
    this.textContent = 'Something';
  }
})
.caret {
  display: inline-block; width: 0; height: 0; margin-left: 2px; vertical-align: middle; border-top: 4px dashed; border-top: 4px solid\9; border-right: 4px solid transparent; border-left: 4px solid transparent;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
  People <span class="caret"></span>
</button>