How to collapse section using Javascript on single click? - javascript

I know this question has been asked multiple times and I have tried different things which are not working.
All I want to do is collapse a section on the click of a button, but I have to click button twice before it actually collapses
(In CollapseGrid is getting printed twice and then it goes to In Collapse).
How do we make it work in one go without having to click twice?
function collapseGrid(element) {
console.log("In CollapseGrid");
element.addEventListener("click", collapse);
};
function collapse() {
console.log("In Collapse");
var content = this.nextElementSibling;
if (content.style.display === "block") {
content.style.display = "none";
} else {
content.style.display = "block";
}
}
<button class="info" onClick="collapseGrid(this)">CLICK</button>
<div class="contnet">
<p>This should be collapsed.</p>
</div>

Your section gets collapsed on the second click because on the first click you are simply assigning a click listener, but not really executing the collapse function. The code you included inside collapseGrid() should be written outside of the function. Then just make the button invoke collapse() rather than collapseGrid().
document.querySelector(".info").addEventListener("click", collapse);
function collapse(e) {
var content = e.nextElementSibling;
if (content.style.display === "block") {
content.style.display = "none";
} else {
content.style.display = "block";
}
}
<button class="info" onClick="collapse(this)">CLICK</button>
<div class="contnet" style="display:block">
<p>This should be collapsed.</p>
</div>

Here is a simple way to achieve it with a fairly generic function and a some data attributes.
var elements = document.querySelectorAll('[data-toggle="collapse"]');
elements.forEach(element => element.addEventListener('click', collapse));
function collapse() {
var target = this.getAttribute('data-target');
var element = document.getElementById(target);
element.style.display = element.style.display == "none" ? "block" : "none";
}
<div>
<button class="info" data-toggle="collapse" data-target="collapse1">CLICK 1</button>
<div class="content" id="collapse1">
<p>This should be collapsed.</p>
</div>
</div>
<div>
<button class="info" data-toggle="collapse" data-target="collapse2">CLICK 2</button>
<div class="content" id="collapse2">
<p>This should be collapsed.</p>
</div>
</div>

Why don't you simply collapse the next element in the collapseGrid function? e.g.
function collapseGrid(me) {
var content = me.nextElementSibling;
content.style.display = content.style.display == "none" ? "block" : "none";
}
<button class="info" onClick="collapseGrid(this)">CLICK</button>
<div class="content">
<p>This should be collapsed.</p>
</div>

Related

Javascript hide/show with many elements

in my HTML i have questions and solutions. I want to hide and show solutions for each question with different buttons.
Here is my problem: I am writing a new function for each solution button. For example if i have 100 questions then i need to write 100 different Javascript function.
Is there any better way for doing this. Can i write only one function for each solution button.
Thank you very much in advance.
Here is my html:
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success"
onclick="myFunction()">Solution</button>
<div id="Solution">
<div class="highlight">
<pre>
X is apple
</pre>
<li>Question 2. What is y?</li>
<button class="btn btn-outline-success"
onclick="myFunction1()">Solution</button>
<div id="Solution1">
<div class="highlight">
<pre>
Y is orange
</pre>
And here is my Javascript:
document.getElementById( 'Solution' ).style.display = 'none';
function myFunction() {
var x = document.getElementById('Solution');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
document.getElementById( 'Solution1' ).style.display = 'none';
function myFunction1() {
var x = document.getElementById('Solution1');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Note:I saw many questions about hide and show but i could not solve my problem. If this is a duplicate question please warn me and i can remove.
You can reuse a single function by passing an argument that identifies which element in the document should be shown/hidden:
document.getElementById( 'Solution' ).style.display = 'none';
// The function now expects to be passed the ID of the element
function myFunction(elementID) {
var x = document.getElementById(elementID);
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Now, you can call the function repeatedly and just pass different element id's each time:
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success" onclick="myFunction('Solution')">Solution</button>
<div id="Solution">
<div class="highlight">
<pre>X is apple</pre>
</div>
</div>
<li>Question 2. What is y?</li>
<button class="btn btn-outline-success" onclick="myFunction('Solution1')">Solution</button>
<div id="Solution1">
<div class="highlight">
<pre>Y is orange</pre>
</div>
</div>
Now, having said that, you should avoid using inline HTML event attributes (onclick, onmouseover, etc.) whenever possible. There are many reasons why. Additionally, instead of repeatedly setting inline styles, you can make this much simpler by toggling the use of a pre-existing CSS class. Also, your HTML syntax is invalid.
Here's what a cleaned up, valid and modern version of your code would look like. All you have to do is copy the HTML structure of a question and the existing JavaScript will immediately work for it. Each question no longer even needs a name ("Solution1", "Solution2", etc.).
// Get all the buttons in a node list
var theButtons = document.querySelectorAll(".btn-outline-success");
// Turn node list into a JS Array
var buttonArray = Array.from(theButtons);
// Loop over the buttons and give each its click event handler
buttonArray.forEach(function(button){
button.addEventListener("click", function(){
// We will pass a reference to the current button to the function
myFunction(this);
});
});
// The function now expects to be passed a reference to the button that was clicked
function myFunction(element) {
// Get a reference to div that follows the button and then search that div
// for the first pre element inside of it:
var answer = element.nextElementSibling.querySelector("pre");
// All we need to do is toggle the visibility of that pre element
answer.classList.toggle("hidden");
}
/* This class will simply be added or removed to show/hide elements */
/* All answers have this applied by default*/
.hidden {
display:none;
}
li { margin-bottom:10px; }
<!--
NOTES:
1. The onclick has been removed (it is now handled in JavaScript)
2. The quesiton names ("Solution", "Solution1", etc.) are no longer needed
3. Your HTML structure was invalid. Here is the proper way to make bulleted lists.
-->
<ul>
<li>Question 1. What is x?
<button class="btn btn-outline-success">Solution</button>
<div>
<div class="highlight">
<pre class="hidden">X is apple</pre>
</div>
</div>
</li>
<li>Question 2. What is y?
<button class="btn btn-outline-success">Solution</button>
<div>
<div class="highlight">
<pre class="hidden">Y is orange</pre>
</div>
</div>
</li>
<li>Question 3. What is z?
<button class="btn btn-outline-success">Solution</button>
<div>
<div class="highlight">
<pre class="hidden">z is mango</pre>
</div>
</div>
</li>
</ul>
If I understood what you want, you can use parameters.
HTML
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success" onclick="myFunction(1)">Solution</button>
<div id="Solution"></div>
<div class="highlight"></div>
<pre>
X is apple
</pre>
JS
function myFunction(var solNumber = 1) {
var x = document.getElementById('Solution'+solNumber);
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
If all the questions appear in the same time, you could use a for loop to show them all too.
You can do something like this:
Enclose the question in a div with class 'question' and similarly solution enclosed with class 'solution'.
Also define a single show function with parameter as the button element clicked, which passed by using this as parameter in the onclick of button.
The function simply finds the sibling div with class 'solution' and makes it visible by setting display: block
function show_solution(buttonElement) {
questionDiv = buttonElement.parentNode;
if (questionDiv.querySelector('.solution').style.display == 'none') {
questionDiv.querySelector('.solution').style.display = 'block';
} else {
questionDiv.querySelector('.solution').style.display = 'none';
}
}
.solution {
display: none;
}
.highlight {
background: #FF0;
}
<div class="question">
• Question 1. What is x?
<button class="btn btn-outline-success" onclick="show_solution(this)">Solution</button>
<div class="solution">
<div class="highlight">
<pre> X is apple </pre>
</div>
</div>
</div>
<div class="question">
• Question 2. What is y?
<button class="btn btn-outline-success" onclick="show_solution(this)">Solution</button>
<div class="solution">
<div class="highlight">
<pre> Y is orange </pre>
</div>
</div>
</div>
Well, if jquery was allowed, the solution could look like this:
$('.Solution').hide()
$('button').on('click',function(){$(this).next().show()})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success">Solution</button>
<div class="Solution">
<div class="highlight">
<pre>
X is apple
</pre>
</div></div>
<li>Question 2. What is y?</li>
<button class="btn btn-outline-success">Solution</button>
<div class="Solution">
<div class="highlight">
<pre>
Y is orange
</pre>
</div></div>
Note: this would also simplify your html ... But, of course, the choice is yours!

Toggle box wont work with button, but works with paragraph

Im trying to make a toggle menu, however when i insert a <button> tag instead of a <p> tag the whole menu doesn't work, but it works with <p>.
How can i solve this problem?
Snippet:
function toggleMenu() {
var menuBox = document.getElementById('menu-box');
if (menuBox.style.display == "block") { // if is menuBox displayed, hide it
menuBox.style.display = "none";
} else { // if is menuBox hidden, display it
menuBox.style.display = "block";
}
}
<div id="infobox2">
<form action="index.html" method="get">
<p onclick="toggleMenu()" id="menu"> Skapa konto </p>
<ul id="menu-box" style="display: block">
<li>Start</li>
<li>Animal</li>
<li>Pictures</li>
</ul>
</form>
</div>
The default behaviour of a button tag is to send the form. This is why the page is being reloaded. If you don't want the button to send the form, you have to specify a type attribute.
<button type="button">Toggle</button>
Further reading:
https://www.w3schools.com/tags/att_button_type.asp
Especially this part:
Tip: Always specify the type attribute for the element.
Different browsers may use different default types for the
element.
You have to prevent the default behaviour for the button . Just add return false in your function.
function toggleMenu() {
var menuBox = document.getElementById('menu-box');
if (menuBox.style.display == "block") { // if is menuBox displayed, hide it
menuBox.style.display = "none";
} else { // if is menuBox hidden, display it
menuBox.style.display = "block";
}
return false;
}
<div id="infobox2">
<form action="index.html" method="get">
<p onclick="toggleMenu()" id="menu"> Skapa konto </p>
<button onclick="toggleMenu()" id="menu1">Skapa konto1</button>
<ul id="menu-box" style="display: block">
<li>Start</li>
<li>Animal</li>
<li>Pictures</li>
</ul>
</form>
</div>

toggle text by clicking on hyperlink

I need to toggle the text on/Off in html without hiding any of the disabled functions. The following code can toggle on and off but the problem is this:
It cannot toggle without hiding another word. I.e. when I press turn on it hides The Turn Off function.
When I add the toggle method for another line item it only toggles the first line item. So it doesn't matter if I add it to line items five rows past the original it will only trigger the original.
function toggle() {
var ele = document.getElementById("toggleText");
var text = document.getElementById("displayText");
if (ele.style.display == "block") {
ele.style.display = "none";
text.innerHTML = "On";
} else {
ele.style.display = "block";
text.innerHTML = "Turn Off";
}
}
<h1>Services</h1>
<h2>Subscribed Services</h2>
<ul>
<li>Geolocation -<a id="displayText" href="javascript:toggle();">On</a>
<div id="toggleText" style="display: none"></div>
</li>
<li>E-Mail Messaging -<a id="displayText" href="javascript:toggle();">On</a>
<div id="toggleText" style="display: none"></div>
</li>
</ul>
What am I doing wrong?
First of all some annotation to your code:
IDs have to be unique ! So use classes instead.
I hope I understand it correctly what you are trying to achieve:
HTML:
<h2>Subscribed Services</h2>
<ul>
<li>Geolocation -<a class="displayText" href="javascript:void(0);">On</a>
</li>
<li>E-Mail Messaging -<a class="displayText" href="javascript:void(0);">On</a>
</li>
</ul>
JS
$('.displayText').on('click', function(e) {
$(this).text(function(i, s) {
return s === 'On' ? 'Off' : 'On';
});
});
Example
Reference:
.text()

Show/Hide div using javascript without page refresh

I have a script that shows /hides multiple independent divs on a page. The problem is that when you click to show a div, no matter where on the page, it will automatically focus on the first div. Is there a way to focus on the div that was displayed?
here is the javascript:
function toggleOptions(e) {
var ele = e;
var text = e.parentElement.querySelector('.toggleOptions')
if(text.style.display == "none") {
//ele.style.display = "none";
text.style.display = "block";
text.innerHTML = "TESTING";
ele.innerHTML = "hide";
}
else {
text.style.display = "none";
//text.innerHTML = "Hide GPS";
ele.innerHTML = "show";
}
return false;
}
here is the html:
<div>
<a href="#" onclick="toggleOptions(this);" style="display:block;">
show
</a>
<div class="toggleOptions" style="display: none">
ITEM 1 OPTIONS
</div>
</div>
<div>
<a href="#" onclick="toggleOptions(this);" style="display:block;">
show
</a>
<div class="toggleOptions" style="display: none">
ITEM 2 OPTIONS
</div>
</div>
<div>
<a href="#" onclick="toggleOptions(this);" style="display:block;">
show
</a>
<div class="toggleOptions" style="display: none">
ITEM 3 OPTIONS
</div>
</div>
here is a jfiddle of the work http://jsfiddle.net/YE6XZ/1/
Give your show links a class, like:
<a class="show" href="#" onclick="toggleOptions(this);" style="display:block;">show</a>
Then add this to your jQuery:
$('a.show').click(function(e){
e.preventDefault();
});
The default action for a bookmark anchor (href="#") is to jump to the top of the page. This would prevent that. jsFiddle example
An alternative, jQuery-less method would be to change your onclicks to:
onclick="return toggleOptions(this);"
As you are already returning false. jsFiddle example
I believe you could also use the .focus() method to focus on a given element. In your example:
function toggleOptions(e) {
var ele = e;
var text = e.parentElement.querySelector('.toggleOptions')
if(text.style.display == "none") {
//ele.style.display = "none";
text.style.display = "block";
text.innerHTML = "TESTING";
text.focus(); //This should give focus to the newly shown text element
ele.innerHTML = "hide";
}
else {
text.style.display = "none";
//text.innerHTML = "Hide GPS";
ele.innerHTML = "show";
}
return false;
}
Unless I am misunderstanding what you are looking to do....
use javascript:void(0) in href. Use javascript functions to show or hide using id
Show

Hide/Show a div in a list

I have a list with an arbitrary number of items. Each item has a number of actions that can be done onto it. I want to display those actions in a div that appears when the user clicks a link associated with the specific list item.
I have tried the following code but when I click the link it just shows the first hidden div and not the hidden div associated with the link.
<script language="javascript">
function toggleOptions() {
var ele = this;
var text = this.parentNode.getElementsByClassName("displayOptions");
if(ele.style.display == "block") {
ele.style.display = "none";
text.innerHTML = "TESTING";
}
else {
ele.style.display = "block";
text.innerHTML = "Hide GPS";
}
}
HERE IS THE HTML. The list could be endless though, this is just an excerpt of the list.
<a href="javascript:toggleOptions();">
ITEM 1 OPTIONS
</a>
<div class="toggleOptions" style="display: none">
ITEM 1 OPTIONS
</div>
<a href="javascript:toggleOptions();">
ITEM 2 OPTIONS
</a>
<div class="toggleOptions" style="display: none">
ITEM 2 OPTIONS
</div>
<a href="javascript:toggleOptions();">
ITEM 3 OPTIONS
</a>
<div class="toggleOptions" style="display: none">
ITEM 2 OPTIONS
</div>
put another div or something around each group: ... put the toggleOptions() function to onclick and pass the href a # so that it is not empty... pass toggleOptions(this) to know which element is clicked
<div>
<a href="#" onclick="toggleOptions(this);" style="display:block;">
SHOW
</a>
<div class="toggleOptions" style="display: none">
ITEM 1 OPTIONS
</div>
</div>
<div>
<a href="#" onclick="toggleOptions(this);" style="display:block;">
SHOW
</a>
<div class="toggleOptions" style="display: none">
ITEM 2 OPTIONS
</div>
</div>
<div>
<a href="#" onclick="toggleOptions(this);" style="display:block;">
SHOW
</a>
<div class="toggleOptions" style="display: none">
ITEM 3 OPTIONS
</div>
</div>​
try with this here http://jsfiddle.net/YE6XZ/1/
function toggleOptions(e) {
var ele = e;
var text = e.parentElement.querySelector('.toggleOptions')
if(text.style.display == "none") {
//ele.style.display = "none";
text.style.display = "block";
text.innerHTML = "TESTING";
ele.innerHTML = "hide";
}
else {
text.style.display = "none";
//text.innerHTML = "Hide GPS";
ele.innerHTML = "show";
}
return false;
}
.toggleOptions is not a valid id DOM attribute value. Are you trying to get an element by its className? Then you should use getElementsByClassName instead, or remove the leading dot in the literal.

Categories