I'm using the HTML5 tag details for a FAQ section of a pany. An issue was that if the user opened another question the other question would not close automatically. Therefore I searched on the web and found the following solution:
function thisindex(elm){
var nodes = elm.parentNode.childNodes, node;
var i = 0, count = i;
while( (node=nodes.item(i++)) && node!=elm )
if( node.nodeType==1 ) count++;
return count;
}
function closeAll(index){
var len = document.getElementsByTagName("details").length;
for(var i=0; i<len; i++){
if(i != index){
document.getElementsByTagName("details")[i].removeAttribute("open");
}
}
}
This code does work properly in some sense but it has some small issues. Sometimes it opens two questions at the same time and works funny. Is there a method so this can work properly? This should work on desktop, tablet and mobile.
NOT DESIRED EFFECT:
I created a fiddle / with all the code. The javascript is doing it's work there, ig you want to see it live click here.
I'm using the HTML5 tag details for a FAQ section of a pany. An issue was that if the user opened another question the other question would not close automatically. Therefore I searched on the web and found the following solution:
function thisindex(elm){
var nodes = elm.parentNode.childNodes, node;
var i = 0, count = i;
while( (node=nodes.item(i++)) && node!=elm )
if( node.nodeType==1 ) count++;
return count;
}
function closeAll(index){
var len = document.getElementsByTagName("details").length;
for(var i=0; i<len; i++){
if(i != index){
document.getElementsByTagName("details")[i].removeAttribute("open");
}
}
}
This code does work properly in some sense but it has some small issues. Sometimes it opens two questions at the same time and works funny. Is there a method so this can work properly? This should work on desktop, tablet and mobile.
NOT DESIRED EFFECT:
I created a fiddle http://jsfiddle/877tm/ with all the code. The javascript is doing it's work there, ig you want to see it live click here.
Share Improve this question edited Aug 20, 2021 at 9:22 Toto 91.5k63 gold badges95 silver badges132 bronze badges asked Nov 16, 2013 at 20:39 Daniel Ramirez-EscuderoDaniel Ramirez-Escudero 4,04713 gold badges46 silver badges81 bronze badges5 Answers
Reset to default 6Since you tagged jQuery, you can just do this:
$('.info').on('click', 'details', function () {
$('details').removeAttr('open');
$(this).attr('open', '');
});
All this does is remove the open
attribute of all detail
tags when you click on any detail
, and then reopen the one you just clicked on.
http://jsfiddle/877tm/3/
the hole thisindex function is stupid and can be removed. You can simply pass the details element to closeAll.
The closeAll is quite stupid, too it searches for details in the for loop, wow.
// closeAll
function closeAll (openDetails){
var details = document.getElementsByTagName("details");
var len = details.length;
for(var i=0; i<len; i++){
if(details[i] != openDetails){
details[i].removeAttribute("open");
}
}
}
In case you want write clean code.
- You should use $.on or addEventlistener.
- Try to be in a specific context and only manipulate details in this context. (What happens, if you want to have two accordion areas. Or some normal details on the same site, but not inside of the group.)
- Only search for details in the group, if details was opened not closed.
- Give the boolen open property some love, instead of using the content attribute
I made small fiddle, which trys to do this.
To make details as accordion tag you can use below jquery.
$("#edit-container details summary").click(function(e) {
var clicked = $(this).attr('aria-controls');
closeAll(clicked);
});
function closeAll (openDetailid){
$("#edit-container details" ).each(function( index ) {
var detailid = $(this).attr('id');
var detailobj = document.getElementById(detailid);
if (openDetailid != detailid ) {
detailobj.open = false;
}
});
$('html, body').stop().animate({ scrollTop: $('#'+openDetailid).offset().top -100 }, 1000);
}
I had an issue with the answer provided by @MattDiamant where Firefox was removing the open attribute but was not putting the open attribute on the selected detail. I made a small change to his code so it targeted the ID of the currently selected detail element.
Now when I click on a <details>
element then click on another, it collapses the first element and displays the second.
$('details').click(function(e){
$('details').removeAttr('open');
$(e.currentTarget.id).attr('open', '');
});
I have a solution with jQuery
$('details').on('click', function(ev){ //on a '<details>' block click
ev.preventDefault(); //prevent the default behavior
var attr = $(this).attr('open');
if (typeof attr !== typeof undefined && attr !== false){ //if '<details>' block is open then close it
$(this).removeAttr('open');
}else{ // if '<details>' block is closed then open the one that you clicked and close all others
var $that = $(this); //save the clicked '<details>' block
$(this).attr('open','open'); //open the '<details>' block
$('details').each(function(){ //loop through all '<details>' blocks
if ($that.is($(this))){ //check if this is the one that you clicked on, if it is than open it or else close it
$(this).attr('open','open');
}else{
$(this).removeAttr("open");
}
});
}
});