1

I have an html which looks like below

<div class="img-row">

    <div class="img-column move">
        <img class="demo" src="/image/001.jpg">
    </div>

    <div class="img-column move"> 
        <img class="demo" src="/image/002.jpg">
    </div>

    <div class="img-column move moving">
        <img class="demo" src="/image/003.jpg">
    </div>

    <div class="img-column move">.   
        <img class="demo" src="/image/004.jpg">
    </div>

</div>

As you can see I have four child divs under the parent div .img-row which contains the class .move and the third child div contains an additional class .moving. I want to select all the child before the child containing .moving class. Note any child could contain the .moving class and in any scenarios I want all the children before it.

So this is what I do

document.querySelectorAll('.move:not(.moving)')

But it also selects the last child in this case. How do I ensure only the children before the class .moving is selected using javascript?

I found a similar question in stackoverflow Select all elements before element with class? but the solution provided is in css. I want a javascript solution instead.

Souvik Ray
  • 2,899
  • 5
  • 38
  • 70

2 Answers2

2

I don't think you can get it in a single selector because the :not() pseudo-class doesn't allow reaching beyond self :scope. So I'd do it with a simple recursive function to populate an array.

const moving = document.querySelector('.moving')
const befores = getBefores(moving)
console.log(befores.length)

function getBefores(element, array = []) {
  const previous = element.previousElementSibling
  if(!previous)
    return array.reverse()
  array.push(previous)
  return getBefores(previous, array)
}
<div class="img-row">

    <div class="img-column move">
        <img class="demo" src="/image/001.jpg">
    </div>

    <div class="img-column move"> 
        <img class="demo" src="/image/002.jpg">
    </div>

    <div class="img-column move moving">
        <img class="demo" src="/image/003.jpg">
    </div>

    <div class="img-column move">
        <img class="demo" src="/image/004.jpg">
    </div>

</div>
Sheraff
  • 5,730
  • 3
  • 28
  • 53
2

You could use convert NodeList to Array and then slice to the first index of element that has moving class

const allElements = Array.from(document.querySelectorAll('.move'))
const expectedElements = allElements.slice(
  0,
  allElements.findIndex(element => element.classList.contains('moving'))
)

console.log(expectedElements.length)
<div class="img-row">

  <div class="img-column move">
    <img class="demo" src="/image/001.jpg">
  </div>

  <div class="img-column move">
    <img class="demo" src="/image/002.jpg">
  </div>

  <div class="img-column move moving">
    <img class="demo" src="/image/003.jpg">
  </div>

  <div class="img-column move">.
    <img class="demo" src="/image/004.jpg">
  </div>

</div>
hgb123
  • 13,869
  • 3
  • 20
  • 38