not open second menu of accordion menu - javascript

I am using this accordion menu.
JavaScript:
var acc = document.getElementsByClassName("accordion"), i;
for (i = 0; i < acc.length; i++) {
acc[i].onclick = function(){
this.classList.toggle("active");
this.nextElementSibling.classList.toggle("show");
}
}
Html:
<!DOCTYPE html>
<html>
<head>
<style>
button.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
button.accordion.active, button.accordion:hover {
background-color: #ddd;
}
button.accordion:after {
content: '\02795';
font-size: 13px;
color: #777;
float: right;
margin-left: 5px;
}
button.accordion.active:after {
content: "\2796";
}
div.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: 0.6s ease-in-out;
opacity: 0;
}
div.panel.show {
opacity: 1;
max-height: 500px;
}
</style>
</head>
<body>
<h2>Accordion with symbols</h2>
<p>In this example we have added a "plus" sign to each button. When the user clicks on the button, the "plus" sign is replaced with a "minus" sign.</p>
<button class="accordion">Section 3</button>
<div id="foo" class="panel">
<p>
<button class="accordion">Section 3</button>
<div id="foo" class="panel">
<p></p>
</div>
</p>
</div>
</body>
</html>
I need to use the second menu in section 3. I add in this accordion menu to another accordion menu but it does not open. Any ideas why? How can I solve this problem?

In the following HTML structure, I'm replacing P tag with DIV tag. The P element cannot contain block level elements like DIV.
Ref: How can I put DIV in P? and P tag
<body>
<h2>Accordion with symbols</h2>
<p>In this example we have added a "plus" sign to each button. When the user clicks on the button, the "plus" sign is replaced with a "minus" sign.</p>
<button class="accordion">Section 3</button>
<div id="foo" class="panel">
<div>
<button class="accordion">Section 3</button>
<div id="foo" class="panel">
<div>
test
</div>
</div>
</div>
</div>
</body>
The click event didn't work for your original HTML structure, as the browser altered the DOM elements and DIV element was removed from inside of P tag(explained the reason with the above reference links). This DOM change has resulted in an issue while we retrieve nextElementSibling.
Accept this answer if it solves your issue.

Related

How can i select a specific element after i've clicked another element in the same div [duplicate]

This question already has answers here:
Cleanest way to get the next sibling in jQuery
(3 answers)
Closed 2 years ago.
I have a h3 element and a p element which are inside a div element ,like this:
<div class="question">
<h3> *a question* <img class="arrow" src="" alt="an-arrow-img"> </img> </h3>
<p> *an answer* </p>
</div>
And I have a class named "show" in my css file, which looks like this:
//shows the answer when I click the h3 element
.show{
display: block;
}
on the website, I'm trying to make the questions-answers look like this:
show-hide p element
I've used javascript to toggle the class "show" when I click the questions (h3 elements) but I toggle them all and can't figure out how i can select the one I've clicked. My javascript code is this one till now:
$("h3").on("click", function(){
$("p").toggleClass("show");
});
Is it my HTML structure that's wrong, or is there a way to combine the $(this) selector to show the answer only to the question I've clicked?
var question = document.getElementsByClassName("question");
var i;
for (i = 0; i < question.length; i++) {
question[i].addEventListener("click", function() {
this.classList.toggle("active");
var answer = this.nextElementSibling;
if (answer.style.maxHeight) {
answer.style.maxHeight = null;
} else {
answer.style.maxHeight = answer.scrollHeight + "px";
}
});
}
.question {
background-color: #2d6596;
color: #f1f1f1;
cursor: pointer;
padding: 18px;
width: 100%;
border: 1px solid white;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active, .question:hover {
background-color: #1a364f;
}
.question:after {
content: '\002B';
color: #f1f1f1;
font-weight: bold;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2212";
}
.answer {
padding: 0 18px;
background-color: #f2f2f2;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
<button class="question">The question</button>
<div class="answer">
<p>The answer</p>
</div>
<button class="question">The question</button>
<div class="answer">
<p>The answer</p>
</div>
<button class="question">The question</button>
<div class="answer">
<p>The answer</p>
</div>
Use JQuery.next() to select sibling of $this.
$("h3").on("click", function(){
$(this).next("p").toggleClass("show");
});

Collapside opening upwards

I am new to coding and I want to have like these panels on the bottom of the page that when pressed it opens some menu with buttons and stuff and I think the best choice would be collapside. But after reading the W3schools tutorial I didn´t find any reference on how to make them open pointing up. I hope it just don´t move the whole page and just opens a clickable window. If not I would like to know which other thing to use for that. Here is the code from W3schools
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
}
.active, .collapsible:hover {
background-color: #555;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2212";
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h2>Animated Collapsibles</h2>
<p>A Collapsible:</p>
<button class="collapsible">Open Collapsible</button>
<div class="content">
<p>upper one (only one is enought).</p>
</div>
<p>Collapsible Set:</p>
<button class="collapsible">Open Section 1</button>
<div class="content">
<p>1.</p>
</div>
<button class="collapsible">Open Section 2</button>
<div class="content">
<p>2.</p>
</div>
<button class="collapsible">Open Section 3</button>
<div class="content">
<p>3.</p>
</div>
</body>
</html>
You should set your content variable to previousElementSibling to get the element before.
var content = this.previousElementSibling;
Then, swap the order of the collapse button and content like so:
<div class="content">
<p>upper one (only one is enought).</p>
</div>
<button class="collapsible">Open Collapsible</button>
JSFiddle: https://jsfiddle.net/gf72yw8q/
The reason they open downwards is because the html structure and css is indicating for it to be that way, for example:
<p>A Collapsible:</p>
<button class="collapsible">Open Collapsible</button>
<div class="content">
<p>upper one (only one is enought).</p>
</div>
The <p> with the text "upper one" (in this case your content) appears after open <button>.
If you want it to open upwards, the content would thus need to appear (in the html) before the button (to avoid using additional css styles to reproduce the intended effect).
for example:
<ul class="magic-content">
<li>an example list item</li>
<li>another example item</li>
</ul>
<a class="magic-button" href="#">my magic button</a>
to make this work, you would then need something like this inside your js file. For the purpose of this example, I am using jquery:
//FILTERS RESET
$('.magic-button').click(function(event) {
event.preventDefault;
$('.magic-content').toggleClass('on');
});
And your css would need to have something such as:
.magic-content {display:none;}
.magic-content.on {display:block;}
So that the toggling of the class 'on' is what triggers the showing/hiding of the content.
ALTERNATIVELY, the example you are referring to can be found here:
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_toggle_class_crossbrowser
And all you need to do in their example to reverse the order is change the order of the html elements:
<div id="myDIV">
This is a DIV element.
</div>
<button onclick="myFunction()">Try it</button>
The button after the content. I hope this helps.
G

Accordion inside a form auto submits

So disclaimer, I already found the answer to this but I'm posting it as a question in case it helps somebody else.
Scenario: Inside a form in the page you have a couple of accordions so that the user can collapse the parts they already looked at. If you follow most examples expanding the accordions will actually auto submit the form, no bueno.
<!DOCTYPE html>
<html>
<head>
<style>
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active, .accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
</style>
</head>
<body>
<h2>Accordion</h2>
<form action="fail" method="post" enctype="multipart/form-data">
<button class="accordion">Section 1</button>
<div class="panel">
<input type="checkbox" name="checkbox1.1">Checkbox 1.1
<br>
<input type="checkbox" name="checkbox1.2">Checkbox 1.2
</div>
<button class="accordion">Section 2</button>
<div class="panel">
<input type="checkbox" name="checkbox2.1">Checkbox 1.1
<br>
<input type="checkbox" name="checkbox2.2">Checkbox 1.2
</div>
<input type="submit" value="Submit">
</form>
<script>
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
</script>
</body>
</html>
Essentially the buttons for the accordion are being treated as submit buttons even though we already have a submit button. In order to override this behavior simply declare the button type as button:
<button type="button" class="accordion">Section 1</button>
<button type="button" class="accordion">Section 2</button>
This may be obvious to some but given that I rarely deal with web stuff this was a very frustrating side affect to find and work around so I hope it helps somebody else.

Make a div keeping its size when hiding elements in the DOM

I have dynamically created divs. For some tests, I go for 30 divs.
Each div got a button bar at the bottom. I just want to show this bar, when hovering the div container.
When hiding these elements, the div gets smaller / is shrinking down. I want to keep this bigger size, so only the buttons are hidden but the container keeps its size.
When leaving the div, only the buttons should disappear.
#wrapper{
padding: 50px;
background-color: red;
}
#content{
color: white;
padding: 10px;
font-size: 20px;
}
#wrapper:hover .btn{
display:block;
}
.btn{
display:none;
}
<div id="wrapper">
<div id="content">
content
</div>
<div>
<button class="btn">
Button 1
</button>
<button class="btn">
Button 2
</button>
<button class="btn">
Button 3
</button>
</div>
</div>
Use visibility to control the visibility of the elements. It hides the elements but keeps their occupied area, maintaining the box model, in the page.
#wrapper{
padding: 50px;
background-color: red;
}
#content{
color: white;
padding: 10px;
font-size: 20px;
}
#wrapper:hover .btn{
visibility:visible;
}
.btn{
visibility:hidden;
}
<div id="wrapper">
<div id="content">
content
</div>
<div>
<button class="btn">
Button 1
</button>
<button class="btn">
Button 2
</button>
<button class="btn">
Button 3
</button>
</div>
</div>
Use visibility instead of display
Visibility will keep the element space. display will remove the space
#wrapper{
padding: 50px;
background-color: red;
}
#content{
color: white;
padding: 10px;
font-size: 20px;
}
#wrapper:hover .btn{
visibility:visible;
}
.btn{
visibility:hidden;
}
<div id="wrapper">
<div id="content">
content
</div>
<div>
<button class="btn">
Button 1
</button>
<button class="btn">
Button 2
</button>
<button class="btn">
Button 3
</button>
</div>
</div>
you can try both these methods as per your need:
1, Only CSS
Using opacity.
#wrapper{
padding: 50px;
background-color: red;
}
#content{
color: white;
padding: 10px;
font-size: 20px;
}
#wrapper:hover .btn{
opacity:1;
}
.btn{
opacity:0;
}
<div id="wrapper">
<div id="content">
content
</div>
<div>
<button class="btn">
Button 1
</button>
<button class="btn">
Button 2
</button>
<button class="btn">
Button 3
</button>
</div>
</div>
1, CSS and JQUERY
Uisng the code in your Q, only added a class test-height
var firstHeight = $('.test-height').height();
$('.test-height').height(firstHeight);
$('.btn').hide();
#wrapper{
padding: 50px;
background-color: red;
}
#content{
color: white;
padding: 10px;
font-size: 20px;
}
#wrapper:hover .btn{
display:block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
<div id="content">
content
</div>
<div class="test-height">
<button class="btn">
Button 1
</button>
<button class="btn">
Button 2
</button>
<button class="btn">
Button 3
</button>
</div>
</div>
Hope this helps.ty

Angular JS - HTML Accordion breaking in ng-repeat

I need some little help with some template I'm working on for my project.
I found this code for an accordion container on the internet:
/* Toggle between adding and removing the "active" and "show" classes when the user clicks on one of the "Section" buttons. The "active" class is used to add a background color to the current button when its belonging panel is open. The "show" class is used to open the specific accordion panel */
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].onclick = function () {
this.classList.toggle("active");
this.nextElementSibling.classList.toggle("show");
}
}
/* Style the buttons that are used to open and close the accordion panel */
button.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: 1px solid lightgray;
outline: none;
transition: 0.4s;
}
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
button.accordion.active, button.accordion:hover {
background-color: #ddd;
}
/* Style the accordion panel. Note: hidden by default */
div.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: 0.6s ease-in-out;
opacity: 0;
}
/* The "show" class is added to the accordion panel when the user clicks on one of the buttons. This will show the panel content */
div.panel.show {
opacity: 1;
max-height: 500px;
}
button.accordion:after {
content: "+"; /* Unicode character for "plus" sign (+) */
font-size: 13px;
color: #777;
float: right;
margin-left: 5px;
}
button.accordion.active:after {
content: "-"; /* Unicode character for "minus" sign (-) */
}
<button class="accordion">Section 1</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
<button class="accordion">Section 2</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
<button class="accordion">Section 3</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
It works fine, looks nice, exactly what I wanted. But when I try to do something like this:
<div ng-repeat="category in categories">
<button class="accordion">{{category.name}}</button>
<div class="panel">
<p>{{category.description}}</p>
</div>
</div>
the tabs don't open anymore. I can't find the problem. Can anyone give me a solution to this?
Thank you.
Here is a different approach to do this:
Add ng-click to the button to toggle the class active of him.
Change the .show selector to button.active + div.panel so you can change only the button class.
angular.module('app', []).controller('ctrl', function($scope) {
$scope.categories = [];
for (var i = 1; i <= 3; i++) {
$scope.categories.push({
name: 'cat' + i,
description: 'description' + i
});
}
});
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].onclick = function(){
this.classList.toggle("active");
this.nextElementSibling.classList.toggle("show");
}
}
button.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
button.accordion.active, button.accordion:hover {
background-color: #ddd;
}
div.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: 0.6s ease-in-out;
opacity: 0;
}
button.active + div.panel {
opacity: 1;
max-height: 500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<h2>Animated Accordion</h2>
<div ng-app="app" ng-controller="ctrl">
<div ng-repeat="category in categories">
<button class="accordion" data-ng-click="category.active = !category.active" data-ng-class="{'active': category.active}">{{category.name}}</button>
<div class="panel">
<p>{{category.description}}</p>
</div>
</div>
</div>
var app = angular.module('app',[]);
app.controller('mycontroller',function($scope){
$scope.categories = [{name:'Lorem ipsum...'},{name:'Lorem ipsum...'},{name:'Lorem ipsum...'}]
});
<html ng-app='app'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.min.js"></script>
</head>
<body ng-controller='mycontroller'>
<div ng-repeat="category in categories">
<button ng-class="accordion">{{category.name}}</button>
<div ng-class="panel">
<p>{{category.description}}</p>
</div>
</div></body>
</html>

Categories

Resources