Reputation: 4102
I try to understand how to remove all children elements without specified attribute for example:
This is the html:
<div class="container">
<span></span>
<div></div>
<strong data-*></strong>
<p></p>
<div data-*></div>
</div>
What i want is to remove all element inside the container and without data-* attribute.
data-*
The attribute can be data-anything (data-color, data-border, etc).
I'm looking javascript only solution.
Upvotes: 2
Views: 383
Reputation: 318212
This should do it
var parent = document.querySelector('.container');
var elems = parent.querySelectorAll('*');
for (var i=elems.length; i--;) {
var attr = elems[i].attributes,
hasData = false;
for (var j = attr.length; j--;) {
if ( attr[j].name.indexOf('data') === 0 ) {
hasData = true;
break;
}
}
if ( ! hasData ) parent.removeChild(elems[i]);
}
querySelector(All)
will have to be polyfilled if you need to support IE7 and below.
Upvotes: 2
Reputation: 10972
Using .filter()
, .some()
and .forEach()
should do the trick.
var els = document.querySelectorAll(".container *");
[].filter.call(els, function(el) {
return ![].some.call(el.attributes, function(attr) {
return /^data/i.test(attr.name);
});
}).forEach(function(el) {
el.parentNode.removeChild(el);
});
You'll need patches for old browsers, but you probably knew that already.
If like me, you like reusable functions:
var els = document.querySelectorAll(".container *");
[].filter.call(els, els_with_no_data)
.forEach(remove_nodes);
function remove_nodes(el) {
el.parentNode.removeChild(el);
}
function has_data_attrs(attr) {
return /^data/i.test(attr.name);
}
function els_with_no_data(el) {
return ![].some.call(el.attributes, has_data_attrs)
}
And then using Array generics (in supported browsers, otherwise polyfiilled):
var els = document.querySelectorAll(".container *");
Array.filter(els, els_with_no_data)
.forEach(remove_nodes);
function remove_nodes(el) {
el.parentNode.removeChild(el);
}
function has_data_attrs(attr) {
return /^data/i.test(attr.name);
}
function els_with_no_data(el) {
return !Array.some(el.attributes, has_data_attrs)
}
Upvotes: 4
Reputation: 14304
Reworked solution of @cookie monster
:
(function r (nodelist) {
// reduceRight is used only to walk in reverse direction
[].reduceRight.call(nodelist, function (dummy, e) {
if ([].every.call(e.attributes, function(a) {
return !/^data/i.test(a.name);
})) return e.parentNode.removeChild(e);
r(e.children);
}, "filler");
}(document.getElementsByClassName("container")[0].children));
Upvotes: 2
Reputation: 207511
There is probbaly better ways, just had a few minutes to waste so thought I would play with the answer.
var container = document.getElementsByClassName("container")[0];
var children = container.childNodes;
for (var i=children.length-1;i--) {
var child = children[i];
if (child.nodeType===1) { //make sure it is an element, not a text node
var hasMatch = false;
var attrs = child.attributes; //get the attributes of the element
for(var j=0; j<attrs.length;j++){ //loop through
if(attrs[j].nodeName.indexOf("data-")===0) { //if it starts we have a match
hasMatch = true;
break;
}
}
if (!hasMatch) {
container.removeChild(child); //if no match, remove it
}
}
}
Upvotes: 2
Reputation: 10132
Try this:
var objects = document.querySelectorAll('.container *');
var parent = document.getElementsByClassName('container')[0];
for (var i = objects.length - 1; i >= 0; i--) {
if (objects[i].attributes[0]) {
if (objects[i].attributes[0].name.indexOf('data-') == -1) {
parent.removeChild(objects[i]);
}
} else {
parent.removeChild(objects[i]);
}
}
Upvotes: 1