This question maybe stupid for many here. I have a bunch of divs and want to make them appear/disappear on click with special behaviour:
On-load state: all divs visible
click: all divs disappear, except for the one that was selected when clicking
to n-th click: toggle visibility for the div that was selected when clicking
What I've got so far:
function toggle_visibility(id) {
var e = document.getElementById(id);
if(e.style.display == 'block')
e.style.display = 'none';
else
e.style.display = 'block';
}
function toggle_class(id) {
var thisElem = document.getElementById(id);
var invisible = "invisible";
var visible = "visible";
var classes = thisElem.classList;
if (classes == invisible) {
thisElem.className = thisElem.className.replace(invisible, visible);
}
else {
thisElem.className = thisElem.className.replace(visible, invisible);
}
}
<ul id='list'>
<li id='1-i' class='visible'>Toggle DIV #1</li>
<li id='2-i' class='visible'>Toggle DIV #2</li>
<li id='3-i' class='visible'>Toggle DIV #3</li>
<li id='4-i' class='visible'>Toggle DIV #4</li>
</ul>
<div id='1' style='display: block;'><h3>DIV #1</h3></div>
<div id='2' style='display: block;'><h3>DIV #2</h3></div>
<div id='3' style='display: block;'><h3>DIV #3</h3></div>
<div id='4' style='display: block;'><h3>DIV #4</h3></div>
This code shows all divs on page-load, then toggles visibility for the selected div on click. So on first click only the selected div will disappear with all others staying still visible - the opposite of what I want. Though from second click on, this behaviour is the desired one.
I have found similar other threads (like this one), but their issues seem to add complexity I'd like to avoid.
Thanks a lot for your help!
Edit:
Now I tried to update function toggle_class(id) { following Arun P Johny's example:
var firstrun = true;
function toggle_class(id) {
var thisElem = document.getElementById(id);
var invisible = "invisible";
var visible = "visible";
if (thisElem.className == 'invisible' && !firstrun) {
thisElem.className = thisElem.className.replace(invisible, visible);
} else {
thisElem.className = thisElem.className.replace(visible, invisible);
}
if (firstrun) {
var children = document.getElementsByClassName('visible');
for (var i = 0; i < children.length; i++) {
if (children[i].id != id) {
children[i].className = thisElem.className.replace(visible, invisible);
}
}
}
firstrun = false;
}
The result is somewhat confusing: On first click, the selected element changes its class to invisible (which I do understand, since the script tries to replace the class visible with invisible for all elements). So this is not the behaviour I want, the clicked element is supposed to keep the class visible (until it is clicked again, since this is when the div disappears).
And the even more confusing part to me: Not all other elements change their class to invisible, but only every second element.
What did I do wrong?
Overly simplified version: http://jsfiddle.net/9ref3cf2/
HTML
<ul id='list'>
<li data-id="1">Toggle DIV #1</li>
<li data-id="2">Toggle DIV #2</li>
<li data-id="3">Toggle DIV #3</li>
<li data-id='4'>Toggle DIV #4</li>
</ul>
<div data-id='1' class="listBlock"><h3>DIV #1</h3></div>
<div data-id='2' class="listBlock"><h3>DIV #2</h3></div>
<div data-id='3' class="listBlock"><h3>DIV #3</h3></div>
<div data-id='4' class="listBlock"><h3>DIV #4</h3></div>
JavaScript
function toggleListBlocks() {
$('.listBlock').hide();
$('.listBlock[data-id='+ $(this).data('id') +']').show();
}
$(document).ready(function(){
$('#list>li').click(toggleListBlocks);
});
One approach is to assign a class to all the toggled div elements and use them to fetch and hide them
<div id='1' class="toggle" style='display: block;'><h3>DIV #1</h3></div>
<div id='2' class="toggle" style='display: block;'><h3>DIV #2</h3></div>
<div id='3' class="toggle" style='display: block;'><h3>DIV #3</h3></div>
<div id='4' class="toggle" style='display: block;'><h3>DIV #4</h3></div>
then
var first = true;
function toggle_visibility(id) {
var e = document.getElementById(id), toggle;
if (e.style.display == 'block' && !first) {
e.style.display = 'none';
} else {
e.style.display = 'block';
var children = document.getElementsByClassName('toggle');
for(var i = 0; i<children.length; i++){
if(children[i].id != id){
children[i].style.display = 'none';
}
}
}
first = false;
}
Demo: Fiddle
Using classList, you may have to include a shim to support older browsers
<div id='1' class="toggle"><h3>DIV #1</h3></div>
<div id='2' class="toggle"><h3>DIV #2</h3></div>
<div id='3' class="toggle"><h3>DIV #3</h3></div>
<div id='4' class="toggle"><h3>DIV #4</h3></div>
then
var first = true;
function toggle_visibility(id) {
var thisElem = document.getElementById(id);
var classes = thisElem.classList;
if (classes.contains('hidden') || first) {
classes.remove('hidden');
var children = document.getElementsByClassName('toggle');
for (var i = 0; i < children.length; i++) {
if (children[i].id != id) {
children[i].classList.add('hidden');
console.log('x')
}
}
} else {
classes.add('hidden');
}
first = false;
}
Demo: Fiddle
Related
What I want to achieve is, when hovering over the li with id="a", the corresponding ul with id="aa" appears. I have this html code:
<ul>
<li id="1">Option1</li>
<li id="2">Option2</li>
</ul>
<ul id="11">
<li>Option1.1</li>
<li>Option1.2</li>
</ul>
<ul id="22">
<li>Option2.1</li>
<li>Option2.2</li>
</ul>
and this javascript code:
for (i=1; i<3; i++) {
var fn = (function(i) {
var li = document.getElementById(i);
var ul = document.getElementById("" + i + i);
li.addEventListener("mouseover", function() {
ul.style.opacity = "1";
}, false);
})(i);
}
and it works as expected, but here the user Jordan Gray stated that it is possible to get rid of the loop and instead create one event listener for all list items - that is what I would like to achieve here. Unfortunately I do not understand his code and would be thankful if anyone could explain it to me or suggest a solution.
Here is how you can use that logic in your code:
var ul = document.getElementById('ul-id');
ul.addEventListener('mouseover', function(e) {
if (e.target.nodeName.toUpperCase() !== "LI") return;
document.getElementById("" + e.target.id + e.target.id).style.opacity = "0.6";
});
<ul id="ul-id">
<li id="1">Option1</li>
<li id="2">Option2</li>
</ul>
<ul id="11">
<li>Option1.1</li>
<li>Option1.2</li>
</ul>
<ul id="22">
<li>Option2.1</li>
<li>Option2.2</li>
</ul>
Await hovering a LI, Then display its corresponding element:
window.addEventListener("mouseover",function(e){
var el = e.target;
if(el.id && parseInt(el.id) < 10){
document.getElementById(el.id*11).style.opacity = 0.7;
}
});
You can add an event listener for the parent ul and ase the target element in this listener in order to know on which li it triggered.
ctn.addEventListener('mouseover', function(event) {
// eventually safeguard it with: if (event.target.tagName !== 'LI') return
id = event.target.id.repeat(2)
document.getElementById(id).style.opacity = 1
}, false);
.passive {
opacity: 0;
}
<ul id="ctn">
<li id="a">Option1</li>
<li id="b">Option2</li>
</ul>
<ul id="aa" class="passive">
<li>Option1.1</li>
<li>Option1.2</li>
</ul>
<ul id="bb" class="passive">
<li>Option2.1</li>
<li>Option2.2</li>
</ul>
Here is the concept of my content being shown/hidden. It also works.
https://jsfiddle.net/mplungjan/a7Lfjsgh/
It works in the small html code above. However, it does not work when I apply it to my larger HTML code. Does someone know why?
My goal is to have many list items with spans attached to the reveal answers button.
HTML:
<nav class="Rightbox" id="RightFrench">
<div id="Stage1">
<h1>Stage 1</h1>
<h5> <span class="HighlightBlue">Exercise 1 - </span></h5>
<h5><button class="AnswerTitle" id="AnswersFrenchStage1Ex1">Reveal Answers</button></h5>
<p class="Task">
<span class="HighlightBlue">Translate the following</span>
</p>
<ul>
<li>
<p> the passeport <textarea></textarea>
<span class="FrenchStage1Ex1">la passeport</span>
</p>
</li>
<li>
<p>the passeport <textarea></textarea>
<span class="FrenchStage1Ex1">la passeport</span>
</p>
</li>
</div>
</nav>
Javascript:
window.onload = function() {
var buttons = document.querySelectorAll(".AnswerTitle");
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = function() {
var id = this.id.replace(/reveal/, "FrenchStage");
var answers = document.querySelectorAll("." + id);
for (var i = 0; i < answers.length; i++) {
answers[i].style.display = answers[i].style.display == "inline" ? "none" : "inline";
}
}
}
}
CSS:
.Rightbox ul li p span {display:none;}
the problem turns out to be I changed the id of the button, thinking that the javascript was not using the button id. turns out the
var id = this.id.replace(/reveal/, "FrenchStage")
really wanted the button to have an ID containing "reveal"
I have some links that will show a div when clicking it. When clicking another link, it should show the link's associated div and hide the previously shown div.
HTML
Text 1
Text 2
Text 3
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
Javascript
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
}
CSS
.hidden { display: none; }
.unhidden { display: block; }
How can I accomplish this?
Try with:
function unhide(divID) {
var unhidden = document.getElementsByClassName('unhidden');
for (var k in unhidden) {
unhidden[k].className='hidden';
}
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
}
You can do something like this :
function unhide(divID) {
var divs = document.getElementsByTagName('div');
foreach(var div in divs){
div.className = 'hidden';
if(div.id == divID)
div.className = 'unhidden';
}
}
Be careful with document.getElementsByTagName('div');, it will return you all divs on your document. You could adapt it using a wrapper.
For example :
HTML
<div id="wrapper">
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
</div>
JS :
var divs = document.getElementById('wrapper').getElementsByTagName('div');
Try this http://jsfiddle.net/L79H7/1/:
function unhide(divID) {
var divIds = [ "text1", "text2", "text3" ];
for ( var i = 0, len = divIds.length; i < len; i++) {
var item = document.getElementById(divIds[i]);
if (item) {
item.className = divID == divIds[i] ? 'unhidden' : 'hidden';
}
}
}
You could also store in an array the names of the divs you want to hide and iterate over it when unhiding one:
var divs= new Array("text1", "text2", "text3");
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
for (var i in divs){
if (divs[i] != divID){
item = document.getElementById(divs[i]);
if (item) {
item.className='hidden';
}
}
}
}
JSFiddle
You don't need exactly links for this, but if you insist change it to:
<a href="#" onclick='unhide("text3");'>Text 3</a>
Otherwise you can change it to:
<p onclick="unhide('text1')">Text 1</p>
<p onclick="unhide('text2')">Text 2</p>
<p onclick="unhide('text3')">Text 3</p>
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
And your function should look like this to add or remove classes:
function unhide(id){
yourElement = document.getElementById(id);
if(yourElement.className == "unhidden"){
yourElement.className = "hidden";
}else{
yourElement.className = "unhidden";
}
}
demo
<div id="text1" class="hidden"> 1 </div>
<div id="text2" class="hidden"> 2 </div>
<div id="text3" class="hidden"> 3 </div>
.hidden{ display:none; }
#text1{ display: block; }
function show(id) {
var item = document.getElementById(id);
var all = document.getElementsByClassName('hidden');
for(var i=0; i<all.length; i++)all[i].style.display = 'none';
if(item)item.style.display = 'block';
}
you can use jquery try the code below and import the jquery library first
$('#text1').show();
$('#text2').hide();
it is the easiest way
Anyone can tell me why even though by debugging with fireBug the script correctly finds the proper element, the style.display doesn't update the property of the ul which remains set to none?
<html>
<div id="nav">
<ul>
<li>Studio
</li>
</ul>
</div>
<div id="subnav1">
<ul style="display: none">
<li>normally hidden
</li>
</ul>
</div>
<script type="text/javascript" src="jquery-1.4.3.min.js"></script>
<script type="text/javascript">
function show()
{
var subNav1 = document.getElementById("subnav1");
var ull = subNav1.getElementsByTagName("ul");
for (var i = 0, ii = ull.length; i < ii; i++)
{
if(ull[i].style.display == "visible")
{
ull[i].style.display = "none";
}
else
{
ull[i].style.display = "visible";
}
}
};
</script>
</html>
"visible" is not a valid css display value. I think you are looking for "block"
I have Javascript tabs which show/hide divs instead of loading new pages. The tabs have a style which gives a hover effect. I now want to add an active style to match up with the curently visible div.
THE JAVASCRIPT, which does not work as it is from a version which loads pages:
function setActive() {
aObj = document.getElementById('nav').getElementsByTagName('a');
for(i=0;i < aObj.length;i++) {
if(document.location.href.indexOf(aObj[i].href) >= 0) {
aObj[i].className='active';
}
}
}
function showdiv(id){
document.getElementById(id).style.display = "block";
}
function hidediv(id){
document.getElementById(id).style.display = "none";
}
THE STYLE:
#pageAdmin { display:block; }
#userAdmin { display:none; }
THE HTML:
<ul id="nav">
<li><a onclick="showdiv('pageAdmin'); hidediv('userAdmin')"
href="#">Page Admin</a></li>
<li><a onclick="showdiv('userAdmin'); hidediv('pageAdmin')"
href="#">User Admin</a></li>
</ul>
<div id="pageAdmin">
<h1>Page admin</h1>
</div>
<div id="userAdmin">
<h1>User admin</h1>
</div>
This is my first question on SO, so I hope it is appropriate - please accept my apologies in advance if it is not!
Your setActive function isn't very helpful. And using location, href and hash it will be hard doing what you want.
You may change your script to
function showdiv(id){
var el = document.getElementById(id);
el.style.display = "block";
el.className = "active";
}
function hidediv(id){
var el = document.getElementById(id);
el.style.display = "none";
el.className = "";
}
Now it should do what you want.
However, you should take a look on jQuery.
Using jQuery you do eliminate the use of getElementById and you can much simpler attach an eventhandler for onclick's, as by using vanilla js. It is considered as bad practice to setup handlers in html attributes.
jQuery also handles you the splitting and joining the space separated className string, if you want to use multiple styles.
Using jQuery it looks like:
$("a", "#nav").click(function () {
var $navA = $(this);
var tabName = $navA.attr("data-tabName");
$(".tab").each(function () {
var $tab = $(this);
if ($tab.attr("id") === tabName) {
$tab.css({ display: 'block' }); // you may move this into active style
$tab.addClass("active");
$tab.removeClass("inactive");
}
else {
$tab.css({ display: 'none' }); // you may move this into inactive style
$tab.removeClass("active");
$tab.addClass("inactive");
}
});
});
The HTML for the jQuery example
<ul id="nav">
<li><a data-tabName="pageAdmin" href="#">Page Admin</a></li>
<li><a data-tabName="userAdmin" href="#">User Admin</a></li>
</ul>
<div class="tab" id="pageAdmin">
<h1>Page admin</h1>
</div>
<div class="tab" id="userAdmin">
<h1>User admin</h1>
</div>