wrap()
alone will not work, if you want to wrap a group of elements (the input and the "/12" text node) , as it wraps each one individually.
You need to find the relevant nodes, i.e. the input and text nodes, detach()
them from the DOM, append()
them to your new span, then append the span to the original div.
You can include text nodes by using contents()
and checking the nodeType
as described in this answer.
jQuery
With full jQuery, this isn't too bad:
$('.side').append(function() {
// create the span, add the detached nodes to it, then append to the container
$('<span class="page-count"/>').append($(this).contents().filter(function(){
// filter() contents down to textNodes and the input element, then detach() them all in one jQuery object
return((this.nodeType === 3 && this.textContent.trim().length > 0)
|| (this.tagName && this.tagName.toUpperCase() === 'INPUT'))
}).detach()).appendTo(this);
});
$('.side').append(function() {
// create the span, add the detached nodes to it, then append to the container
$('<span class="page-count"/>').append($(this).contents().filter(function(){
// filter() contents down to textNodes and the input element, then detach() them all in one jQuery object
return((this.nodeType === 3 && this.textContent.trim().length > 0)
|| (this.tagName && this.tagName.toUpperCase() === 'INPUT'))
}).detach()).appendTo(this);
});
span.page-count {
border:1px solid red;
padding:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="side">
<a>Link 1</a>
<a>Link 2</a>
<input value="1"/>
/ 12
</div>
Angular
With jqLite, it's not quite as neat. Just replacing $(this)
with angular.element(this)
doesn't work, even though most of these jQuery functions are supported in jqLite. The problem comes down to filter()
being unsupported, which makes it awkward to detach()
all the necessary elements in one go.
I got around this by changing the statement above into a forEach()
and detach/appending one at a time:
// store the '.side' container
var sideElem = angular.element(document.querySelectorAll('.side'));
// create the new span
var pageCount = angular.element('<span class="page-count"/>');
// loop through contents of '.side'
angular.forEach(sideElem.contents(), function(val) {
// if node matches, detach() it from '.side' and append() to the span
if((val.nodeType === 3 && val.textContent.trim().length > 0)
|| (val.tagName && val.tagName.toUpperCase() === 'INPUT')) {
pageCount.append(angular.element(val).detach());
}
});
// add the span to the '.side' container
sideElem.append(pageCount);
// store the '.side' container
var sideElem = angular.element(document.querySelectorAll('.side'));
// create the new span
var pageCount = angular.element('<span class="page-count"/>');
// loop through contents of '.side'
angular.forEach(sideElem.contents(), function(val) {
// if node matches, detach() it from '.side' and append() to the span
if((val.nodeType === 3 && val.textContent.trim().length > 0)
|| (val.tagName && val.tagName.toUpperCase() === 'INPUT')) {
pageCount.append(angular.element(val).detach());
}
});
// add the span to the '.side' container
sideElem.append(pageCount);
span.page-count {
border:1px solid red;
padding:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div class="side">
<a>Link 1</a>
<a>Link 2</a>
<input value="1"/>
/ 12
</div>