I have encountered a problem with expandable divs. Here is my code:
HTML:
<div>more...</div>
<div class="expand" style="display:none">
YO DAWgGG
</div>
JS:
<script type="text/javascript" charset="utf-8">
function showHide(elementid){
if (document.getElementsByClassName("expand").style.display == 'none'){
document.getElementsByClassName("expand").style.display = '';
} else {
document.getElementsByClassName("expand").style.display = 'none';
}
}
</script>
It says that expand is undefined. But I don't see why. What am I doing wrong? Same code works if i use an ID but i need this for more than one div.
Thanks!
You need to do document.getElementsByClassName("expand")[0] as getElementsByClassName returns an array of object.
function showHide(el){
if (document.getElementsByClassName(el)[0].style.display == 'none'){
document.getElementsByClassName(el)[0].style.display = '';
} else {
document.getElementsByClassName(el)[0].style.display = 'none';
}
}
<div>more...</div>
<div class="expand" style="display:none">
YO DAWgGG
</div>
Based on the existing markup. I recommend to use document.querySelectorAll, and instead of setting an elements style, toggle its class.
var links = document.querySelectorAll('.link');
for (var i=0; i<links.length; i++) {
links[i].addEventListener('click', function(e){
e.target.parentElement.nextElementSibling.classList.toggle('show');
})
}
.expand {
display: none;
}
.expand.show {
display: block;
}
<div><a class="link" href="#">more...</a></div>
<div class="expand">
YO DAWgGG 1111
</div>
<div><a class="link" href="#">more...</a></div>
<div class="expand">
YO DAWgGG 222
</div>
<div><a class="link" href="#">more...</a></div>
<div class="expand">
YO DAWgGG 333
</div>
document.getElementsByClassName returns you a HTMLCollection and not a HTMLElement and hence you cant use .style on the collection.
So, if you need to apply some styling on all elements of the collection, you need to iterate over and apply.
Here is what you could do.
document.addEventListener('DOMContentLoaded', function() {
let anchors = document.querySelectorAll(".more");
[].forEach.call(anchors, (anchor) => {
anchor.addEventListener("click", (event) => {
event.preventDefault();
let parent = event.target.parentNode;
let ele = parent.querySelector(".expand");
if (ele.style.display == 'none') {
ele.style.display = '';
} else {
ele.style.display = 'none';
}
})
})
});
<div><a class="more" href="#">more...</a>
<div class="expand" style="display:none">
YO DAWgGG
</div>
</div>
<div><a class="more" href="#">more-2-...</a>
<div class="expand" style="display:none">
YO DAWgGG-2
</div>
</div>
Related
Looking to remove a class if a certain button is clicked.
<div class="slide-container">
<section class="about" id="slide-0">
<div class="menu-total">
<nav class="nav">
<button class="nav_link home" onclick="slideTo('slide-2')">HOME</button>
<button class="nav_link about" onclick="slideTo('slide-0')">ABOUT</button>
<button class="nav_link fun-stuff" onclick="slideTo('slide-1')">FUN STUFF</button>
<button class="nav_link professional" onclick="slideTo('slide-3')">PROFESSIONAL</button>
<button class="nav_link contact" onclick="slideTo('slide-4')">CONTACT</button>
</nav>
<div class="hamburger">
<span class="hamburger__patty"></span>
<span class="hamburger__patty"></span>
<span class="hamburger__patty"></span>
</div>
</div>
The one I want to remove the class on is the HOME button. So "slideTo('slide-2)". If it's clicked on the others then the class is kept. I believe someone is either wrong with my loop or not getting the ID correctly of the items/
function slideTo(slideId) {
const slide = document.getElementById(slideId);
slide.scrollIntoView({
behavior: 'smooth'
})
// above this line works fine
let nonHome = document.querySelectorAll('.slide-container section');
let nonHomeID = document.getElementById('slide-2');
var i;
setTimeout(function(){
for (i=0; i < nonHome.length; i++ ){
// i believe it's somewhere here it is wrong
if (nonHome[i].id != nonHomeID){
nonHome[i].classList.add("nav-visibility");
} else{
nonHomeID.classList.remove("nav-visibility");
}
}
}, 1000)
}
If you can use jquery library, you can write in the HTML:
<button class="nav_link" data-value="home">HOME</button>
...
and then in the JS code:
$(".nav_link").on("click", function() {
var valueClicked = $(this).data("value"); // Get the data-value clicked
$(".nav_link").each(function() { // Loop through all elements of the class 'nav-link'
var v = $(this).data("value");
if (v == valueClicked) {
$(this).removeClass("nav-visibility");
} else {
$(this).addClass("nav-visibility");
}
)
}
Not much simpler, but the HTML is cleaner.
Simpler version if it is not required to browse through all buttons at each button click:
$(".nav_link").on("click", function() {
var valueClicked = $(this).data("value"); // The value of the button clicked by the user
if (valueClicked == "home") {
$(this).removeClass("nav-visibility");
console.log('remove')
} else { $(this).addClass("nav-visibility");
console.log('add')
}
});
I have a menu which should show the sub-elements organised in a div when clicked.
I provide below the structure of the html
function showOrHide() {
if (window.innerWidth < 800) {
var div = document.getElementById("links");
if (div.style.display == "block") {
div.style.display = "none";
} else {
div.style.display = "block";
}
}
}
<li>
<div id="image" onclick="showOrHide()">
<span>Test1</span>
</div>
<div id="links">
<span>Test2</span>
</div>
</li>
<li>
<div id="image" onclick=" showOrHide()">
<span>Test3</span>
</div>
<div id="links">
<span>Test4</span>
</div>
</li>
I would like the div id="links" to be shown or hidden when I click on div id="image". I have the following javascript.
The problem that I face is that onclick javascript is showing all the divs id=links in the menu and I would like only the div links next to the div image to be shown. Example when I click on Test1 only Test2 should be shown.
Element IDs should be unique within the entire document.
You must try creating unique id per div.
function showOrHide(rowNum)
{ if (window.innerWidth < 800) {
var div = document.getElementById("links_"+ rowNum);
if (div.style.display == "block")
{
div.style.display = "none";
}
else
{
div.style.display = "block";
}
}
}
<li>
<div id="image_1" onclick="showOrHide(1)">
<span>Test1
</span></div>
<div id="links_1">
<span >Test2</span>
</div></li>
<li>
<div id="image_2" onclick=" showOrHide(2)">
<span>Test3
</span></div>
<div id="links_2">
<span >Test4</span>
</div></li>
Change id and structure accordingly.
<li>
<div id="image_1" onclick="showOrHide(1)">
<span>Test1
</span>
</div>
<div id="links_1">
<span >Test2</span>
</div>
</li>
<li>
<div id="image_2" onclick=" showOrHide(2)">
<span>Test3
</span>
</div>
<div id="links_2">
<span >Test4</span>
</div>
</li>
JavaScript:
function showOrHide(rowNumber)
{ if (window.innerWidth < 800) {
var div = document.getElementById("links_"+ rowNumber);
if (div.style.display == "block")
{
div.style.display = "none";
}
else
{
div.style.display = "block";
}
}
}
Just provide a parameter to your showOrHide function which will be the selector for your div and do the toggling to that selector. See the implementation below
<li>
<div id="image" onclick="showOrHide('#links_1')">
<span>Test1</span>
</div>
<div id="links_1">
<span >Test2</span>
</div>
</li>
<li>
<div id="image" onclick=" showOrHide('#links_2')">
<span>Test3</span>
</div>
<div id="links_2">
<span >Test4</span>
</div>
</li>
And the JS:
function showOrHide(divSelector)
{
var div = document.querySelector(divSelector);
if (div.style.display == "none")
{
div.style.display = "block";
}
else
{
div.style.display = "none";
}
}
var elems = document.getElementsByClassName("links");
Array.from(elems).forEach(v => v.addEventListener('click', function() {
this.parentElement.getElementsByClassName('links')[0].classList.toggle('hidden');
}));
.hidden {
display: none;
}
<li>
<div class="links">
<span>Test1 </span>
</div>
<div class="links">
<span>Test2</span>
</div>
</li>
<li>
<div class="links">
<span>Test3
</span></div>
<div class="links">
<span>Test4</span>
</div>
</li>
Your main issue here is that an element's id must be unique to that element. Other elements cannot have the same id. Instead, you can pass through the element into your showOrHide() method using this, and then get the next element using nextElementSibling. This will work provided your HTML structure is consistent:
function showOrHide(elem) {
if (window.innerWidth < 800) {
const div = elem.nextElementSibling;
if (!div.style.display || div.style.display == "block") {
div.style.display = "none";
} else {
div.style.display = "block";
}
}
}
<li>
<div id="image" onclick="showOrHide(this)">
<span>Test1</span>
</div>
<div class="links">
<span>Test2</span>
</div>
</li>
<li>
<div id="image" onclick=" showOrHide(this)">
<span>Test3</span>
</div>
<div class="links">
<span>Test4</span>
</div>
</li>
You can not use the same id lots of time on same HTML. Id attribute is unique, but you can use class.
You can use this code maybe it will help you.
<li>
<div class="image" onclick="showOrHide(this)">
<span>Test1
</span></div>
<div class="links">
<span >Test2</span>
</div></li>
<li>
<div class="image" onclick=" showOrHide(this)">
<span>Test3
</span></div>
<div class="links">
<span >Test4</span>
</div></li>
function showOrHide(element) {
if (window.innerWidth < 800) {
var div = element.closet(".links");
if (div.style.display == "block") {
div.style.display = "none";
} else {
div.style.display = "block";
}
}
}
I have a click event that adds an active class to the link's parentNode. On click the active class should be removed from the siblings of the parentNode. This is the code so far:
categories = document.querySelectorAll('.categories');
for(var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
// ('.categoriesparent').classList.remove('active');
this.parentNode.classList.add('active');
}
I tried the line that is commented out, and that breaks the adding of the class on click. Is there an equivalent to jQuery's siblings().removeClass('active')? Thanks for any help.
Here is the DOM for this section:
<div id="nav">
<span class="categoriesparent active">
<a class="categories">Link</a>
</span>
<span class="categoriesparent">
<a class="categories">Link2</a>
</span>
</div>
UPDATE - this is the original full code snippet:
<html>
<head></head>
<body>
<div id="nav">
<span class="categoriesparent">
Link
</span>
<br><br>
<span class="categoriesparent">
Link2
</span>
</div>
<script>
categories = document.querySelectorAll('.categories');
for(var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
// ('.categoriesparent').classList.remove('active');
this.parentNode.classList.add('active');
}
}
</script>
</body>
</html>
UPDATE after incorporating BRK's code snippet:
<html>
<head></head>
<body>
<div id="nav">
<span class="categoriesparent active">
Link
</span>
<br><br>
<span class="categoriesparent">
Link2
</span>
</div>
<script>
categories = document.querySelectorAll('.categories');
categories.forEach(function(cat, index) {
cat.onclick = function(e) {
document.querySelector('.categoriesparent.active').classList.remove('active');
this.parentNode.classList.add('active');
}
});
</script>
</body>
</html>
Can you try doing like this? It Might help!
categories = document.querySelectorAll('.categories');
for(let i = 0; i < categories.length; i++) {
categories[i].onclick = () => {
// ('.categoriesparent').classList.remove('active');
this.parentNode.classList.add('active');
}
You can first remove the active class from all the siblings of parent (and the parent itself) and then add to the parent
for (var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
[ ...getSiblingsAndMe(this.parentNode) ].forEach( el => el.classList.remove( 'active' ) );
this.parentNode.classList.add('active');
}
}
function getSiblingsAndMe( el )
{
return el.parentNode.children;
}
Demo
categories = document.querySelectorAll('.categories');
for (var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
[ ...getSiblingsAndMe(this.parentNode) ].forEach( el => el.classList.remove( 'active' ) );
this.parentNode.classList.add('active');
}
}
function getSiblingsAndMe( el )
{
return el.parentNode.children;
}
.categoriesparent
{
display:block;
}
.active
{
background-color:pink;
}
<div id="nav">
<span class="categoriesparent active">
<a class="categories">Link</a>
</span>
<span class="categoriesparent">
<a class="categories">Link2</a>
</span>
</div>
Inside the onclick handler you can again use document.querySelector('.categoriesparent.active') . This will return the first matched element and then use classList.remove to remove the active class from it.
this.parentNode refers to the element in context
var categories = document.querySelectorAll('.categories');
categories.forEach(function(cat, index) {
cat.onclick = function(e) {
document.querySelector('.categoriesparent.active').classList.remove('active')
this.parentNode.classList.add('active');
}
})
.active {
color: red;
}
<div id="nav">
<span class="categoriesparent active">
<a class="categories">Link</a>
</span>
<span class="categoriesparent">
<a class="categories">Link2</a>
</span>
</div>
Update from Jamie:
I used your suggestion like so:
<html>
<head></head>
<body>
<div id="nav">
<span class="categoriesparent active">
Link
</span>
<br><br>
<span class="categoriesparent">
Link2
</span>
</div>
<script>
categories = document.querySelectorAll('.categories');
categories.forEach(function(cat, index) {
cat.onclick = function(e) {
document.querySelector('.categoriesparent.active').classList.remove('active');
this.parentNode.classList.add('active');
}
});
</script>
</body>
</html>
I get an "Uncaught TypeError: undefined is not a function" error. Thanks for your input!
I finally figured out what makes the elements I’ve dubbed ‘folders’ to open and close. The issue is when I run the HTML document through the validator, it says attribute <isfolder="true"> not allowed on div element at this point.
<p></p>
<div class="folderOpenClose" onclick="toggleAllFolders();">Open/Close Folders</div>
<p></p>
<div class="folderlabel" onclick="togglefolder('folder0');">Dice Roller</div>
<div id="folder0" class="folder" isfolder="true" style="display: none;">
</div>
<p></p>
<div class="folderlabel" onclick="togglefolder('folder1');">Slide Show</div>
<div id="folder1" class="folder" isfolder="true" style="display: none;">
</div>
<p></p>
<div class="folderlabel" onclick="togglefolder('folder2');">Carousel</div>
<div id="folder2" class="folder" isfolder="true" style="display: none;">
</div>
<p></p>
<div class="folderlabel" onclick="togglefolder('folder3');">Menu Bar</div>
<div id="folder3" class="folder" isfolder="true" style="display: none;">
</div>
<p></p>
The problem with me removing that is it what operates the Open/Close All and when I tried placing the code in the form in the , the Open/Close folder doesn’t work.
var lastChecked = null;
function togglefolder(id){
var ele = object(id);
if(ele.style.display == 'none') ele.style.display='block';
else ele.style.display = 'none';
}
function setAllFolders(how){
var way = ""+how;
if(way == "") way = "none";
if(way == "closed") way = "none";
if(way == "open") way = "block";
var divs = window.document.getElementsByTagName('div');
for(var i=0; i < divs.length; i++){
if(divs[i].getAttribute('data-isfolder')&&divs[i].getAttribute('data-isfolder')=='true')
divs[i].style.display = way;
var thisClass = ""+divs[i].getAttribute('class');
if(thisClass=='folderlabel'){
var thelabel = ""+divs[i].innerHTML;
if(thelabel.indexOf('open/close all folders') != -1)
divs[i].setAttribute('class','folderlabelopen');
}
}
last_toggle=way;
}
<div id="folder2" class="folder" isfolder="true" style="display: none;"></div>
isfolder is not a known HTML property, so it is being flagged.
One solution is to use a data-* attribute such as:
<div id="folder2" class="folder" data-isfolder="true" style="display: none;"></div>
Then your code can use:
if(divs[i].getAttribute('data-isfolder') == 'true')
There is also a nifty dataset API that you could use.
More info on data-* properties.
Hi i currently have two toggles, one is on the sidebar and one is in the main body. They currently work together which is annoying, even though i am using to different scripts. The scripts i am using at the moment for the toggles are almost identical, however, even when using completely different scripts they still work together.
what i mean by work together is when i click the toggle on the main body the side bar toggle reacts.
They are toggles which collapse on oclick.
<script>
var divs = ["Menu", "Add"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<script>
$(document).ready(function () {
// set up the click event
$('.body > a').on('click', function(){
$(this).next('div').siblings('div:not(#Menu)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#Menu').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<!-- sidebar toggle-->
<script>
var divs = ["Order", "Rest", "Franc"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<!-- Change color on click-->
<script>
$(document).ready(function() {
$('.sidebar h3').on('click', function() {
$('.sidebar h3').css('color', 'black');
$(this).css('color', 'red');
});
$('h3#open').trigger('click'); //Your account red on page load
});
</script>
<!--Your account toggle open on load -->
<script>
$(document).ready(function () {
// set up the click event
$('.sidebar > a').on('click', function(){
$(this).next('div').siblings('div:not(#Franc)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#francc').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<div class="sidebar">
<!-- Orders toggle-->
<a id="order" class="header" href="#" onclick="toggleVisibility('Order');"><h3 id="orderr">Orders</h3></a>
<div id="Order" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Red">Overview</li>
</ul>
</div>
</div>
<!--Restaurant toggle-->
<a id="restt" class ="header"href="#" onclick="toggleVisibility('Rest');"><h3>Your Restaurants</h3></a>
<div id="Rest" style="display: none;"><div>
<ul class="tabs">
<!-- <li id="order" class="rred">restaurant</li>-->
<li id="order" class="rgreen">New restaurant</li>
</ul>
</div>
</div>
<!-- Account toggle-->
<a id="francc" name="account" class ="header" href="#" onclick="toggleVisibility('Franc');"><h3 id="open">Your Account</h3></a>
<div id="Franc" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Blue" >Order History</li>
</ul>
</div>
</div>
</div>
<div id=body>
<!-- Menu toggle -->
<div class="container_head"> <!-- red header top of container-->
<a id="Menu" class="header" href="#" onclick="toggleVisibility('Menu');"><h3>Menu Section</h3></a>
</div>
<div id="Menu_form" style="display: none;">
<form id="MenuForm" action ="javascript:void(0);" method="POST">
<!-- <div class="field">-->
<label for="Name">Name</label>
<input type="text" name="Name" id="Name" placeholder="Steaks pattern="[a-zA-Z]"
required tabindex="1">
<br>
<label for="Description">Description</label>
<input type="text" name="Description" id="Description" placeholder="Fresh USDA Choice steaks, seasoned with hickory-smoked sea salt." tabindex="2">
<br>
<div class="field">
<input type="submit" value="Save">
</div>
</form>
</div>
<a id="add_prod" class="header" href="#" onclick="toggleVisibility('Add');"><h3>Orders</h3></a>
<div id="add" style="display: none;">
</div>
Bringing together #j08691 and Leo Farmer's comments, you need to have unique IDs and function names. When you call toggleVisibility(...), it's going to call the second declaration of that method. Also, when you call document.getElementById(...) on something like "order", it's going to stop at the first instance it finds (In your case, the a tag).
Give your functions unique names, give your items unique IDs (if you want them to all do the same thing, you can look at using the same class for each item), and you should be in a better spot.