sazr
sazr

Reputation: 25928

Selector to ignore all elements inside a given class

I am trying to select all elements that are not inside the following divs <div class="manager"></div> or <div class="release"></div>.

So I have made my selector below however it is incorrectly selecting elements inside those above div's. Do you know how I can update my selector to ignore all elements inside <div class="manager"></div> and <div class="release"></div>?

$('*:not(.release, .manager) *').filter(function () { 
   return $(this).css('position') == 'fixed';
}).addClass('reset-pos');

Here is how my html is organised:

<body>
    <div>
        ...
    </div>

    <!-- This element and all below should be ignored/not selected -->
    <div class="manager">
        ...
    </div>

    <!-- This element and all below should be ignored/not selected -->
    <div class="release">
        ...
    </div>
</body>

Upvotes: 1

Views: 621

Answers (3)

Adam Szmyd
Adam Szmyd

Reputation: 2973

You could use xPath and ancestor. Working example:

<body>
    <div class="outside"><div class="outside__child1"></div></div>
    <!-- This element and all below should be ignored/not selected -->
    <div class="manager"><div class="manager__child"></div></div>
    <!-- This element and all below should be ignored/not selected -->
    <div class="release"><div class="release__child"></div></div>
<script>
    const path = "//div[not(contains(@class, 'manager')) and not(contains(@class, 'release')) and not(ancestor::div[contains(@class, 'manager') or contains(@class, 'release')])]"
    const result = document.evaluate(path, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null)
    let node = result.iterateNext();
    while(node) {
        console.log(node);
        node = result.iterateNext();
    }
</script>
</body>

This prints out only div.outside and its child as all others are ignored (I assume you wanted to ignore containers (div.manager and div.release also):

enter image description here

Upvotes: 0

palaѕн
palaѕн

Reputation: 73906

Instead of doing recursive traversing like:

$('*:not(.release, .manager) *')

You can simply do:

$('*:not(.release, .manager, .release *, .manager *)')

Working Demo:

(Note: I am using parent class for this demo, to exclude head and other tags as using * includes everything)

$('.parent *:not(.release, .manager, .release *, .manager *)')
  .addClass('reset-pos');
.reset-pos { border: 1px solid orange; padding: 5px; margin: 5px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
  <div>
    <p>Ouside manager & release</p>
  </div>
  <!-- This element and all below should be ignored/not selected -->
  <div class="manager">
    <p>Inside manager</p>
  </div>
  <!-- This element and all below should be ignored/not selected -->
  <div class="release">
    <p>Inside release</p>
  </div>
</div>


Non-working Demo:

(This demo shows the issue with your selector, without any parent class)

$('*:not(.release, .manager) *').addClass('reset-pos');
.reset-pos { border: 1px solid orange; padding: 3px 8px; margin: 4px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <p>Ouside manager & release</p>
</div>
<!-- This element and all below should be ignored/not selected -->
<div class="manager">
  <p>Inside manager</p>
</div>
<!-- This element and all below should be ignored/not selected -->
<div class="release">
  <p>Inside release</p>
</div>

Upvotes: 2

ehab
ehab

Reputation: 8044

You could use this selector

$('*:not(.manager):not(.release)') // this will get you the results you want

Also i believe this selector will bring results that you dont want like Head, title, meta elements, so i think the following is prorabbly better

$('body *:not(.manager):not(.release)')

Upvotes: 0

Related Questions