Home > OS >  If children has class, add class to specific parent id (pure Javasript), no jQuery
If children has class, add class to specific parent id (pure Javasript), no jQuery

Time:02-27

enter code here

const child = document.querySelectorAll(".accordion span.xh_find");
const parents = document.querySelectorAll('[id^="acc-"]');

if (document.querySelector(".accordion span").classList.contains("xh_find")) {
  
parents.forEach(item => item.classList.add('xh_find_parent'));
// Hm, should not add class to all parents, only if children has ! HowTo?
}
.xh_find_parent {
  background-color: red;
}
<div >

  <div id="acc-1">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-2">
    <p>
      Text without class.
    </p>
  </div>
  
  <div id="acc-3">
    <p>
      Text with <span >class</span>.
    </p>
  </div>
  
  <div id="acc-4">
    <p>
      Text with <span >class</span>.
    </p>
  </div>
  
  <div id="acc-5">
    <p>
      Text without class.
    </p>
  </div>

</div>

How is it possible? The parent id should get the class "xh_find_parent" only if the child element has the class "xh_find". In my code example all are extended with this class.

CodePudding user response:

One approach is as below, explanatory comments in the code:

// we only really need to know two things for this solution,
// although we could also use a variable for the '.accordion';
// the 'needle' is the class-name we're searching for:
const needle = 'xh_find',
// the 'classToAdd' is the class we wish to add to the ancestor
// of the 'xh_find' elements:
      classToAdd = 'xh_find_parent';

// here we use a template-literal to concatenate the 'needle'
// variable into the selector for document.querySelectorAll();
// this is resolved to '.accordion .xh_find'; we then use
// NodeList.prototype.forEach() to iterate over the NodeList:
document.querySelectorAll(`.accordion .${needle}`).forEach(
  // here we use an Arrow function expression, to pass in
  // a reference to the current element-node of the
  // NodeList over which we're iterating,to the body of the
  // function.
  // In the function-body, we retrieve the first of the
  // element's ancestor elements that has an id attribute:
  (el) => el.closest('[id]')
            // and then we use the Element.classList API:
            .classList
            // to add the 'classToAdd' value to the
            // classes of the recovered ancestor:
            .add(classToAdd)
);
/* The CSS is irrelevant to the demo; however:
   this is a simple reset, to have all elmenents
   and pseudo-elements use the same layout, margin,
   padding and font: */
*,
 ::before,
 ::after {
  box-sizing: border-box;
  font: normal 400 1rem / 1.5 sans-serif;
  margin: 0;
  padding: 0;
}

/* using grid layout as that maintains the desired
   layout; but allows the use of 'gap' to place a
   regular space between adjacent elements without
   having to work with margins: */
.accordion {
  display: grid;
  gap: 0.5em;
  /* places a margin on the block axis of the content,
     the top and bottom in left-to-right/top-to-bottom
     languages: */
  margin-block: 1em;
  /* defines the margin on the inline-axis of the content,
     the left and right in left-to-right (and right-to-left)
     languages: */
  margin-inline: auto;
  /* defines the width as 70 viewport-widths (70% of the
     width of the viewport), but sets a minimum width of
     20em and a maximum width of 600px: */
  width: clamp(20em, 70vw, 600px);
}

.xh_find_parent {
  background-color: red;
}
<div >

  <div id="acc-1">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-2">
    <p>
      Text without class.
    </p>
  </div>

  <div id="acc-3">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-4">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-5">
    <p>
      Text without class.
    </p>
  </div>

</div>

JS Fiddle demo.

References:

CodePudding user response:

Once you selected parents:

  • loop them with forEach()
  • for each item of parents, check (with querySelector()) if there is some child with the required class xh_find
  • if exist at least one child with that class, add xh_find_parent class to the item

// 
const parents = document.querySelectorAll('[id^="acc-"]');

parents.forEach(item => {
  const childHasClass = item.querySelector('.xh_find'); // <- yield 'null' if no children with that class

  if (childHasClass) {
    item.classList.add('xh_find_parent');
  }
})
.xh_find_parent {
  background-color: red;
}
<div >

  <div id="acc-1">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-2">
    <p>
      Text without class.
    </p>
  </div>

  <div id="acc-3">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-4">
    <p>
      Text with <span >class</span>.
    </p>
  </div>

  <div id="acc-5">
    <p>
      Text without class.
    </p>
  </div>

</div>

  • Related