How to traverse this structure, simply?

Assuming the following structure (and this can change slightly)

<div class="outer">
  <div class="parent">
    <div tabIndex="0" class="child has-info">1</div>
    <div tabIndex="0" class="child">2</div>
    <div tabIndex="0" class="child has-info">3</div>
    <div tabIndex="0" class="child has-info">4</div>
    <div tabIndex="0" class="child">5</div>
    <div tabIndex="0" class="child has-info selected">6</div>
    <div tabIndex="0" class="child">7</div>
  <div class="parent">
    <div tabIndex="0" class="child">8</div>
    <div tabIndex="0" class="child">9</div>
    <div tabIndex="0" class="child has-info">10</div>
    <div tabIndex="0" class="child has-info">11</div>
    <div tabIndex="0" class="child">12</div>
    <div tabIndex="0" class="child has-info">13</div>
    <div tabIndex="0" class="child has-info">14</div>
.. etc

I’m trying to find the next .child that also has class “has-info”


The problem is that if there are no more siblings in the row that match, I need it to go to the next row. Is there a way to programatically search all of .outer for the next element in the DOM (after .selected) that matches? Every jQuery function I’ve looked at involves siblings and I’d like to avoid having to detect that there’s no matches, traverse up and over to the next .parent and search THOSE children (and so on and so forth - there can be several .parent 's in the real live example.

CSS (and thus, CSS selectors) is, by its nature, unable to go “up”. (You’re not a salmon.)

Chewing it over, here’s my first impulse, but I feel it’s probably reducible. (Also, i’m making the assumption we want to stay in vanilla JS.)

function findNext() {
let trigger = false;
let out = undefined
document.querySelectorAll('.child').forEach(x => {
  if(trigger && x.classList.contains('has-info')) { out = x; trigger = false; }
  if(x.classList.contains('selected')) { trigger = true; }
return out;

Translation: Forget traversing the DOM. Just get a flat list of the desired elements, and walk THAT instead.

I ended up doing this:

nextDay = function(element) {
            const totalRows = element.find(".parent").length;
            const selectedRow = element.find(".selected").parent().index() - 1;
            for(let i = selectedRow; i < totalRows; i++) {
                if(element.find(".parent:eq("+i+") .selected").length) { //first loop
                    if(element.find(".parent:eq("+i+") .selected").is(":last-child") || !element.find(".parent:eq("+i+") .selected").nextAll(".has-info").length) {
                    } else {
                        return element.find(".parent:eq("+i+") .selected").nextAll(".has-info").first();
                } else {
                    if(element.find(".parent:eq("+i+") .has-info").length) {
                        return element.find(".parent:eq("+i+") .has-info").first();

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.