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>
References:
- CSS:
- JavaScript:
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 classxh_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>