Hi,
this code below closes all other detail tags open if one of them gets opened
document.addEventListener('click', function (e) {
const details = [...document.querySelectorAll('details')];
if (!details.some(f => f.contains(e.target))) {
details.forEach(f => f.removeAttribute('open'));
} else {
details.forEach(f => !f.contains(e.target) ? f.removeAttribute('open') : '');
}
});
Thats fine but I want to modify it so it will only close detail tags next to each other (siblings)
document.addEventListener('click', function (e) {
const details = [...document.querySelectorAll('details')];
details.some(f => {
if(f.previousElementSibling && f.previousElementSibling.contains(e.target) || f.nextElementSibling && f.nextElementSibling.contains(e.target)) {
details.forEach(f => f.removeAttribute('open'));
}
});
});
<div id="siblings1">
<details>
<summary>Parent 1</summary>
<details><summary>Child 1</summary>opened</details>
<details><summary>Child 2</summary>opened</details>
<details><summary>Child 3</summary>opened</details>
</details>
<details>
<summary>Parent 2</summary>
<details><summary>Child 1</summary>opened</details>
<details><summary>Child 2</summary>opened</details>
<details><summary>Child 3</summary>opened</details>
</details>
<details>
<summary>Parent 3</summary>
<details><summary>Child 1</summary>opened</details>
<details><summary>Child 2</summary>opened</details>
<details><summary>Child 3</summary>opened</details>
</details>
</div>
but I dont have it down right quite yet (clicking on the child will close its parent which I dont intend).
Goal: you click parent 1 and then child 1, then you click child 2, that should close child 1. Then you click parent 2, which should close parent 1 but its child 2 should remain open.
What is missing?
Thank you.
CodePudding user response:
I think it my be easier if you don't start at document.
const details = document.querySelectorAll('details')
function close_slblings(event) {
event.stopPropagation()
for (let sib of this.parentElement.querySelectorAll(':scope > details'))
if (sib != this)
sib.removeAttribute('open')
// optionally recursively close their children details
}
for (let el of details) {
el.addEventListener('click',close_slblings)
}
details{padding-left: 1em;}
<details>
<summary>Parent 1</summary>
<details>
<summary>Parent 1-1</summary>
<details><summary>Child 1-1-1</summary></details>
<details><summary>Child 1-1-2</summary></details>
<details><summary>Child 1-1-3</summary></details>
</details>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
<details>
<summary>Parent 2</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
<details>
<summary>Parent 3</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
CodePudding user response:
Here comes document
version.
note: you need to find the correct target in this version.
function close_slblings() {
for (let sib of this.parentElement.querySelectorAll(':scope > details'))
if (sib != this)
sib.removeAttribute('open')
// optionally recursively close their children details
}
document.addEventListener('click',e=>{
let target_detail=e.target
while(target_detail && !(target_detail instanceof HTMLDetailsElement)){
target_detail = target_detail.parentElement
}
if(target_detail)
close_slblings.call(target_detail)
})
details{padding-left: 1em;}
<details>
<summary>Parent 1</summary>
<details>
<summary>Parent 1-1</summary>
<details><summary>Child 1-1-1</summary></details>
<details><summary>Child 1-1-2</summary></details>
<details><summary>Child 1-1-3</summary></details>
</details>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
<details>
<summary>Parent 2</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
<details>
<summary>Parent 3</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
something to click on
CodePudding user response:
You can query the details element in the same level instead of querying every node.
document.addEventListener("click", function (e) {
let details = e.target.closest("details");
let childNodes = Array.from(details.parentNode.childNodes);
for (let i = 0; i < childNodes.length; i ) {
let node = childNodes[i];
if(node.tagName === 'DETAILS')
node.removeAttribute("open");
}
details.setAttribute("close");
});
<details>
<summary>Parent 1</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
<details>
<summary>Parent 2</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>
<details>
<summary>Parent 3</summary>
<details><summary>Child 1</summary></details>
<details><summary>Child 2</summary></details>
<details><summary>Child 3</summary></details>
</details>