Aviel Fedida
Aviel Fedida

Reputation: 4102

Remove all element without attribute

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

Answers (5)

adeneo
adeneo

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

FIDDLE

querySelector(All) will have to be polyfilled if you need to support IE7 and below.

Upvotes: 2

cookie monster
cookie monster

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

kirilloid
kirilloid

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

epascarello
epascarello

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

Rahil Wazir
Rahil Wazir

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

Demo

Upvotes: 1

Related Questions