skip to Main Content

I am currently trying to figure out the following situation.

const invalidInput = document.querySelector('.ng-invalid:not(.no-check, .ng-invalid *)');

console.log(invalidInput.name);
<div class="ng-valid no-check">
  <div class="ng-invalid">
    <span>(</span>
    <input class="ng-invalid" name="hello" id="hello">
    <span>)</span>
    <input class="ng-invalid" name="hello2" id="hello2">
  </div>
</div>
<br>
<input class="ng-invalid" name="hello3" id="hello3">

the output should log hello3

here is the fiddle : fiddle

4

Answers


  1. You can use input.ng-invalid:not(div.ng-invalid .ng-invalid)

    Where you are getting all input.ng-invalid that aren’t a child of a div with the class of .ng-invalid.

    const ngInvalid = document.querySelector('input.ng-invalid:not(div.ng-invalid .ng-invalid)');
    console.log(ngInvalid.name)
    <div class="ng-valid no-check">
      <div class="ng-invalid">
        <span>(</span>
        <input class="ng-invalid" name="hello" id="hello">
        <span>)</span>
        <input class="ng-invalid" name="hello2" id="hello2">
      </div>
    </div>
    <br>
    <input class="ng-invalid" name="hello3" id="hello3">
    Login or Signup to reply.
  2. Assuming that your input is inside a div container, you can get your un-nested element by using direct child selector >:

    const invalidInput = document.querySelector('.container > .ng-invalid:not(.no-check)');
    
    console.log(invalidInput.name);
    <div class="container">
      <div class="ng-valid no-check">
        <div class="ng-invalid">
          <span>(</span>
          <input class="ng-invalid" name="hello" id="hello">
          <span>)</span>
          <input class="ng-invalid" name="hello2" id="hello2">
        </div>
      </div>
      <br>
      <input class="ng-invalid" name="hello3" id="hello3">
    </div>
    Login or Signup to reply.
  3. I updated the script to include some extra details. First, querySelectorAll() to determine if the selector was pulling multiple items. Yes. Then I logged the tagname and full classlist.
    Your selector is essentially retrieving items with class .ng-invalid that are NOT nested within elements with that class and do not have .no-check. This matches two items: the first div with ng-invalid and the final input. You are only returning one element, the first one, which is the div. I would suggest adding an "input" tag to your selector, like so.

    const invalidInput = document.querySelectorAll('input.ng-invalid:not(.no-check, .ng-invalid *)');
    
    console.log([...invalidInput].map(i => `${i.tagName}: ${i.classList.value}`));
    <div class="ng-valid no-check">
      <div class="ng-invalid">
        <span>(</span>
        <input class="ng-invalid" name="hello" id="hello">
        <span>)</span>
        <input class="ng-invalid" name="hello2" id="hello2">
      </div>
    </div>
    <br>
    <input class="ng-invalid" name="hello3" id="hello3">
    Login or Signup to reply.
  4. If you are only looking for input elements, then you can filter something like this:

    const invalidInputs = [...document.querySelectorAll('input.ng-invalid')].filter(el => !closestWithoutSelf(el, '.ng-invalid'));
    
    function closestWithoutSelf(el, selector) {
      let parentEl = el.parentElement;
      while (parentEl) {
        if (parentEl.matches(selector)) {
          return parentEl;
        }
        parentEl = parentEl.parentElement;
      }
      return null;
    }
    
    console.log(invalidInputs);
    <div class="ng-valid no-check">
      <div class="ng-invalid">
        <span>(</span>
        <input class="ng-invalid" name="hello" id="hello">
        <span>)</span>
        <input class="ng-invalid" name="hello2" id="hello2">
      </div>
    </div>
    <br>
    <input class="ng-invalid" name="hello3" id="hello3">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search