Nix
Nix

Reputation: 58522

Check if paragraph only has child elements no text

<p id='1'></p>
<p id='1a'><br /></p>
<p id='3success'><b>Match this</b></p>
<p id='3fail'><b>Match this</b> but not now because of this test</p>

I have some logic that needs to skip elements that meet the following conditions

  1. No html
  2. only br or nbsp
  3. Only has child elements of certain type (b,i,img)

I can easily handle 1/2 but the third I am having trouble with. I know how to assert the children part, $('#3fail').children().length but I dont know how to determine if there is additional text.

Any suggestions on how to validate 3? I'm processing the element in a simple .each function

$('p').each(function(){ 
     var element = $(this)
     if(matchesCondition(element)){
        doLogic(element)
     } 
}); 

Note

Someone posted an answer and got a lot of upvotes but it does not work. Here is a fiddle to test out answers.

http://jsfiddle.net/ncapito/k87rc/

I was able to fix @Kolink s answer

http://jsfiddle.net/ncapito/9D3tg/

var getNontextNodes;
//coffeescript generated
getNontextNodes = function (nodes) {
  var cnt, n, _i, _len;
  cnt = 0;
  for (_i = 0, _len = nodes.length; _i < _len; _i++) {
    n = nodes[_i];
    if (n.textContent.trim()) {
      cnt++;
    }
   }
  return cnt;
};

$("p").each(function () {
  if (
    (this.children.length === this.childNodes.length)
   || 
     (getNontextNodes(this.childNodes) === this.children.length)) 
       $(this).append("<b style='color:green'>Success</b>");
  else 
    $(this).append("<b style='color:red'>Failed</b>");
});

Upvotes: 1

Views: 570

Answers (1)

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324650

You can check if an element only has element children by checking
if( this.children.length == this.childNodes.length), because children[] only counts element children, while childNodes[] includes text nodes too.

Once you've cleared this step, you can iterate through the children[] array and check their tagName to see if they're in your list.

EDIT: I've just noticed, this will not allow any whitespace, such as newlines, between elements. If you want to allow whitespace but not actual text, try this check instead:
if( !(this.textContent || this.innerText).match(/\S/))

No, that won't work. This will, though:

var filter = [].filter ? [].filter : function(cb) {for( var i=0, l=this.length, ret=[]; i<l; i++) {if(cb(this[i])) ret.push(this[i]);} return ret;};
$("p").each(function(){
    if( this.children.length == this.childNodes.length || filter.call(this.childNodes,function(n) {return n.nodeType == 3 && n.nodeValue.match(/\S/);}).length == 0)
        $(this).append("<b style='color:green'>Success</b>")
   else
       $(this).append("<b style='color:red'>Failed</b>")
});

Demo

Upvotes: 6

Related Questions