Amir Rahman
Amir Rahman

Reputation: 1119

check for only selected element if that has text in it but not its child

i am trying to check if a selected element have text inside it , the problem is when i am trying to checking value by innerText its also returning values from child which is why boolean function is returning true but what i am expecting to do is just verify one element and avoiding child's i hope i have exlpained it correct so what can be a proper way to achive this

const main = document.querySelector(".main")
const first = main.querySelector(".selected")
const second = main.querySelector(".another")
const third = main.querySelector(".another-one")

function hasText(el){
  return el.innerText != ""
}
console.log(hasText(first),hasText(second),hasText(third)) // true true true expected result is = [true false,true]
<div class="main">
    <div class="selected">
        i have text inside me
    </div>
    <div class="another">
        <div class="child">i am inside a child</div>
    </div>
    <div class="another-one">
        i am inside another one
        <div class="child">i am inside a child</div>
    </div>
  
</div>

Upvotes: 1

Views: 612

Answers (2)

Maik Lowrey
Maik Lowrey

Reputation: 17566

I would test if some tags inside the string. If not you can use your check if is empty.

const main = document.querySelector(".main")
const first = main.querySelector(".selected")
const second = main.querySelector(".another")
const third = main.querySelector(".another2")

function hasText(el) {    
  const pattern = /<.*>.*<\/.*>/;
  return pattern.test(el.innerHTML) ? false : (el.innerText != "");  
}
console.log(hasText(first),hasText(second), hasText(third)) // true true expected result is = [true false true]
<div class="main">
    <div class="selected">
        i have text inside me
    </div>
    <div class="another">
        <div class="child">i am inside a child</div>
    </div>
      <div class="another2">
        i am inside a child
    </div>
</div>

Upvotes: 1

Diego D
Diego D

Reputation: 8163

There are several options to achieve your goal. You could just check if el has children elements and in case .children.length > 0 just consider it as a text container and measure its innerText length.

But in case those parent elements are also supposed to optionally contain both children elements and text, you should check every single childNode of theirs, verify if that's a text portion and consider that text to be part of parent content.Those nodes will be text portions sparse in between legit children elements.

There's also the textContent property of Node that could give you an information similar to that returned by my function grabPureTextContent but there are caveats that I preferred to cut off implementing my own logic.

https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent

Here's a demo adding such function to your code and using its logic to determine if a given element has text content or not.

I added a third case (.special) showing what happens when there's mixed content.

const main = document.querySelector(".main")
const first = main.querySelector(".selected")
const second = main.querySelector(".another")
const third = main.querySelector(".special")

/*
Returns the pure text content defined in el
looping through its childNodes and concatenating content,
(if child is text only) before returning the whole string.

There's also the option to use textContent property of Node
https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
But here the algorithm is more clear on what's going on
*/
function grabPureTextContent(el){
  let content = '';
  for(childText of el.childNodes){
    if (childText.constructor.name == 'Text'){    
      content += childText.nodeValue.trim();
    }
  }
  return content;
}

function hasText(el){      
  if (grabPureTextContent(el).length > 0)
    return true;
  return false;
}

console.log(hasText(third)) //=> true
console.log(hasText(second)) //=> false
console.log(hasText(third)) //=> true
.main > div {
  border: solid 1px gray;
  margin-bottom: 1em;
}

.container {
  background: lightgreen;
}

.child {
  background: lightpink;
}
<div class="main">
    <div class="container selected">
        i have text inside me
    </div>
    <div class="container another">
        <div class="child">i am inside a child</div>
    </div>
    <!-- special case having both children and text -->
    <div class="container special">    
        <div class="child">i am inside a child</div>  
        TEXT HERE after child
    </div>
</div>

Upvotes: 3

Related Questions