Style and change text content of children based on click - javascript

I am trying to style a single div and change the text content based on whether the user clicks on the item or not.
At the moment the code is extremely repetitive and I am looking for a method that will help me rewrite it to both work more efficiently and look cleaner.
Thank you.
let lvl0,
lvl1,
lvl2;
lvl0 = document.querySelector('.level-wrapper').children[0];
lvl1 = document.querySelector('.level-wrapper').children[1];
lvl2 = document.querySelector('.level-wrapper').children[2];
lvl0.addEventListener('click', changeStyle0);
lvl1.addEventListener('click', changeStyle1);
lvl2.addEventListener('click', changeStyle2);
function changeStyle0() {
document.querySelector('.text-header').textContent = levelTitle[0];
var showStyle = document.querySelector('.level-wrapper').children[0];
showStyle.style.opacity = '1';
showStyle.style.backgroundColor = '#95a5a6';
showStyle.style.border = '2px solid white';
showStyle.style.boxSizing = 'border-box';
console.log(showStyle);
}
function changeStyle1() {
document.querySelector('.text-header').textContent = levelTitle[1];
var showStyle = document.querySelector('.level-wrapper').children[1];
showStyle.style.opacity = '1';
showStyle.style.backgroundColor = '#95a5a6';
showStyle.style.border = '2px solid white';
showStyle.style.boxSizing = 'border-box';
console.log(showStyle);
}
function changeStyle2() {
document.querySelector('.text-header').textContent = levelTitle[2];
var showStyle = document.querySelector('.level-wrapper').children[2];
showStyle.style.opacity = '1';
showStyle.style.backgroundColor = '#95a5a6';
showStyle.style.border = '2px solid white';
showStyle.style.boxSizing = 'border-box';
console.log(showStyle);
}
var levelTitle = ["Question about Drinks/Soda/Water.", "Question about Portion Control/Meals.", "Question about Salt/Sugar."];

The method document.querySelector returns you only the first element in the document that fit the selector. To get an array of all the fits elements in the document, you have to use document.querySelectorAll method. For example:
const elements = document.querySelectorAll('.level-wrapper');
elemets[2].children[0].style = ...;
I think that this code is taking care of your issue:
const elements = document.querySelectorAll('.level-wrapper');
function showStyle(index, childIdx) {
elements[index].children[childIdx].style.opacity = '1';
elements[index].children[childIdx].style.backgroundColor = '#95a5a6';
elements[index].children[childIdx].style.border = '2px solid white';
elements[index].children[childIdx].style.boxSizing = 'border-box';
//console.log(levelStyle[index]);
}
function hideStyle(index, childIdx) {
elements[index].children[childIdx].style.opacity = '1';
elements[index].children[childIdx].style.backgroundColor = 'transparent';
elements[index].children[childIdx].style.border = 'none';
elements[index].children[childIdx].style.boxSizing = 'unset';
//console.log(levelStyle[index]);
}
/*for (let i = 0; i < elements.length; i++) {
for (let j = 0; j < elements[i].children.length; j++) {
showStyle(i,j);
}
}*/
for (let i = 0; i < elements.length; i++) {
for (let j = 0; j < elements[i].children.length; j++) {
(function (index) {
elements[i].children[j].onclick = function () {
elements[i].children[j].is_show = !elements[i].children[j].is_show;
if (elements[i].children[j].is_show) {
showStyle(i,j);
} else {
hideStyle(i,j);
}
}
})(j + i*elements[i].children.length);
}
}
<div class="level-wrapper">
<div>aaa</div>
<div>bbb</div>
<div>ccc</div>
<div>ddd</div>
</div>
<br><br>
<div class="level-wrapper">
<div>eee</div>
<div>fff</div>
<div>ggg</div>
<div>hhh</div>
</div>

This method ended up working for me.
Here is the Javascript:
function styleChange() {
const elements = document.getElementsByClassName("level");
for (let i = 0; i < elements.length; i++) {
elements[i].onclick = function () {
let el = elements[0];
while (el) {
if (el.tagName === "LI") {
el.classList.remove("active");
}
el = el.nextSibling;
}
this.classList.add("active");
};
}
}
styleChange();
Here is the html:
<ul class="level-wrapper">
<li class="level">
</a>1</li>
<li class="level">
</a>2</li>
<li class="level">
</a>3</li>
</ul>
And finally the css:
.active {
background-color: #95a5a6;
opacity: 1;
box-sizing: border-box;
border: 2px solid #fff;
}

Related

Implementing wayfinding on dynamic menu

I need help with homework. I need to create a Wayfinder by highlighting an active menu item in a dynamically generated navigation. My code does not respond when a menu item is changed on a button click. Here are my rendered HTML and JavaScript codes.
var urlLink = "http://localhost/acme/products/?action=category&categoryName=Rocket";
var path = urlLink.split("=").pop();
console.log(path);
liContainer = document.getElementById("navMenu");
const navAnchor = liContainer.getElementsByClassName('mainMenu');
/*
navAnchor.forEach(anchor => {
anchor.addEventListener('click', addActive);
});
*/
for (var i = 0; i < navAnchor.length; i++) {
navAnchor[i].addEventListener("click", addActive);
}
function addActive(e) {
var liAnchor = liContainer.target.tagName("a").getAttribute("href");
if (liAnchor.split("=").pop() === path) {
const current = document.querySelector('li.active');
current.className = current.className.replace(" active", "");
e.target.className += " active";
}
}
.active {
background-color: red;
color: white;
padding: 10px
}
<ul id="navMenu">
<li class="mainMenu active">Home</li>
<li class="mainMenu">Cannon</li>
<li class="mainMenu">Explosive</li>
<li class="mainMenu">Misc</li>
<li class="mainMenu">Rocket</li>
<li class="mainMenu">Trap</li>
</ul>
I want the active menu to be highlighted.
I resolved my own issue using the following code:
var path = window.location.href.split("=").pop();
var liContainer = document.getElementById("navMenu");
const navAnchor = liContainer.getElementsByClassName('mainMenu');
for (var i = 0; i < navAnchor.length; i++) {
var liAnchor = navAnchor[i].getElementsByTagName("a");
for (var j = 0; j < liAnchor.length; j++) {
linkPath = liAnchor[j].getAttribute("href").split("=").pop();
if (linkPath === path) {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
navAnchor[i].className += " active";
}
}
}

Remove all #div id from domtree with class .selected

How to remove all divs with id #divs with class .something with vanilla javascript.
For example:
function removeEl() {
var removeEl = document.querySelectorAll('.selected');
if (removeEl.length > 0) {
for (var i = 0; i < removeEl.length; i++) {
var elem = document.getElementById("box1");
elem.remove();
}
}
}
This will delete all div box1 but I want to delete all box1 with class .selected
Simply use:
for (var i = 0; i < removeEl.length; i++) {
removeEl[i].remove();
}
You already selected all elements which you want to remove. So it's not necessary to select it again with a given id.
function removeEl() {
var removeEl = document.querySelectorAll('.selected');
if (removeEl.length > 0) {
for (var i = 0; i < removeEl.length; i++) {
//var elem = document.getElementById("box1");
removeEl[i].parentNode.removeChild(removeEl[i]);
}
}
}

Toggle page color with JS

I'm trying to use JS to change my page's color theme by click a button, and by clicking it again to change it back (i.e. toggle). So far this is my JS code:
var i = 0;
function changeColor() {
if (i%2 == 0) {
switchBlue();
} else {
switchGreen();
}
i++;
}
function switchBlue() {
document.getElementById('color-wrap-01').style.backgroundColor = "#07184a";
document.getElementById('color-wrap-02').style.backgroundColor = "#006385";
document.getElementById('color-wrap-03').style.backgroundColor = "#82baba";
document.getElementById('color-wrap-04').style.backgroundColor = "#082644";
document.getElementById('box').style.backgroundColor = "#d0dddd";
document.getElementById('vl-01').style.borderLeft = "4px solid blue";
document.getElementById('vl-02').style.borderLeft = "4px solid blue";
var footerText = document.getElementsByClassName('footer-text');
for (i = 0; i < 3; i++) {
footerText[i].style.color = "#8eb7ba";
}
var headerText = document.getElementsByClassName('header-text');
for (i = 0; i < 4; i++) {
headerText[i].style.color = "#81babd";
}
var subTitle = document.getElementsByClassName('sub-title');
for (i = 0; i < 11; i++) {
subTitle[i].style.color = "#008688";
}
}
function switchGreen() {
document.getElementById('color-wrap-01').style.backgroundColor = "#074946";
document.getElementById('color-wrap-02').style.backgroundColor = "#00865F";
document.getElementById('color-wrap-03').style.backgroundColor = "#81BA88";
document.getElementById('color-wrap-04').style.backgroundColor = "#084330";
document.getElementById('box').style.backgroundColor = "#D7DDD0";
document.getElementById('vl-01').style.borderLeft = "4px solid green";
document.getElementById('vl-02').style.borderLeft = "4px solid green";
var footerText = document.getElementsByClassName('footer-text');
for (i = 0; i < 3; i++) {
footerText[i].style.color = "green";
}
var headerText = document.getElementsByClassName('header-text');
for (i = 0; i < 4; i++) {
headerText[i].style.color = "green";
}
var subTitle = document.getElementsByClassName('sub-title');
for (i = 0; i < 11; i++) {
subTitle[i].style.color = "green";
}
}
with this html:
<div id="color-wrap-01">
<div class="container">
<div class="row top-header">
<div class="col-sm-6">
<p align="left">Welcome, Guest Login Sign Up</p>
</div>
<div class="col-sm-6">
<p align="right">Stay Updated: Subscribe via RSS Email Updates</p>
</div>
</div>
</div>
AND this button:
<button onclick="changeColor()">COLOUR</button>
The first color change works, but then after that the button doesn't switch back to Green. Any help is appreciated!
If you actually want to toggle between two colors, you can do like this :
var colorSwitch = '';
function changeColor() {
if (colorSwitch === '') {
switchBlue();
colorSwitch = 'blue';
} else {
switchGreen();
colorSwitch = '';
}
}
Thats just an idea, but you may not need an iterator.
You can test that here : https://jsfiddle.net/qwu41fno/

CSS formatting doesn't apply to new tags created by Javascript

I wrote a bunch of JS code to add click listeners to the HTML buttons. I have some CSS that applies to the existing HTML. But the CSS doesn't appear to apply to the HTML generated by the JavaScript.
Link to JSfiddle
As you can see, line 1 has all the proper spacing. But any of the generated lines by clicking any of the three buttons lose the spacing.
Here's the CSS:
.form-block {
padding: 5px;
margin: 5px;
border: 1px solid #000;
span {
padding-right: 15px;
}
}
Thanks for the help in advance! :)
What you see are actual spaces between the elements in your original HTML/row, and then a lack of spaces between the elements in your JS generated elements.
I would either remove the spaces between the elements in your HTML, and use a left/right margin value to create that space instead, or add a space or carriage return/new line between the elements when you add them in your JS.
I removed the spaces (by inserting HTML comments) in your original HTML, and added margin-right: 1em to the input and buttons in your element row.
/*This function interprets the line position.
//input is a lpos string which is in the form of x.x.x.x
//splits it by the '.'
//returns the array with position
*/
function lposToAr(lpos) {
var ar = lpos.split('.');
for (var i = 0; i < ar.length; i++) {
ar[i] = parseInt(ar[i], 10);
}
return ar;
}
//This function turns the position array back into a string
function lposToStr(posAr) {
return posAr.join('.');
}
//This function creates a new line after clicking the NL button.
function NL(lpos, e) {
e.preventDefault();
var cLine = document.getElementsByClassName('line')[0].cloneNode(true);
var cNL = document.getElementsByClassName('new-line')[0].cloneNode(true);
var cNN = document.getElementsByClassName('new-nested')[0].cloneNode(true);
var cI = document.getElementsByClassName('input')[0].cloneNode(true);
cI.value = '';
var cNI = document.getElementsByClassName('new-input')[0].cloneNode(true);
//figure out which position
var posAr = lposToAr(lpos);
var clickNode = document.getElementsByTagName('form')[0];
for (var i = 0; i < posAr.length; i++) {
clickNode = clickNode.children;
var skipCount = 0;
for (var j = 0; j < clickNode.length - 1; j++) {
if (clickNode[j].tagName != 'DIV') {
skipCount++;
}
}
clickNode = clickNode[posAr[i] + skipCount - 1];
}
//set the last element of the posAr the total number of same level <div>+1
var siblingDivCount = 0;
for (var i = 0; i < clickNode.parentNode.children.length; i++) {
if (clickNode.parentNode.children[i].tagName == 'DIV') {
siblingDivCount++;
}
}
var newPosAr = posAr;
newPosAr[newPosAr.length - 1] = siblingDivCount + 1;
//Update the cloned items with the new line info
var newPosStr = lposToStr(newPosAr);
cLine.innerHTML = newPosStr;
cNL.addEventListener('click', function(event) {
NL(newPosStr, event);
});
cNN.addEventListener('click', function(event) {
NN(newPosStr, event);
});
//cI doesn't need to change, unless there's a bug
cNI.addEventListener('click', function(event) {
NI(newPosStr, event);
});
//Make the new Div
var newDiv = document.createElement('div');
newDiv.setAttribute('class', 'form-block');
newDiv.appendChild(cLine);
newDiv.appendChild(cNL);
newDiv.appendChild(cNN);
newDiv.appendChild(cI);
newDiv.appendChild(cNI);
//Add the new Div
clickNode.parentNode.appendChild(newDiv);
}
function NN(lpos, e) {
e.preventDefault();
var cLine = document.getElementsByClassName('line')[0].cloneNode(true);
var cNL = document.getElementsByClassName('new-line')[0].cloneNode(true);
var cNN = document.getElementsByClassName('new-nested')[0].cloneNode(true);
var cI = document.getElementsByClassName('input')[0].cloneNode(true);
cI.value = '';
var cNI = document.getElementsByClassName('new-input')[0].cloneNode(true);
var posAr = lposToAr(lpos);
var clickNode = document.getElementsByTagName('form')[0];
for (var i = 0; i < posAr.length; i++) {
clickNode = clickNode.children;
var skipCount = 0;
for (var j = 0; j < clickNode.length - 1; j++) {
if (clickNode[j].tagName != 'DIV') {
skipCount++;
}
}
clickNode = clickNode[posAr[i] + skipCount - 1];
}
var childDivCount = 0;
for (var k = 0; k < clickNode.children.length; k++) {
if (clickNode.children[k].tagName == 'DIV') {
childDivCount++;
}
}
posAr.push(childDivCount + 1);
//Update the cloned items with the new line info
var newPosStr = lposToStr(posAr);
cLine.innerHTML = newPosStr;
cNL.addEventListener('click', function(event) {
NL(newPosStr, event);
});
cNN.addEventListener('click', function(event) {
NN(newPosStr, event);
});
//cI doesn't need to change, unless there's a bug
cNI.addEventListener('click', function(event) {
NI(newPosStr, event);
});
//Make the new Div
var newDiv = document.createElement('div');
newDiv.className = 'form-block';
newDiv.appendChild(cLine);
newDiv.appendChild(cNL);
newDiv.appendChild(cNN);
newDiv.appendChild(cI);
newDiv.appendChild(cNI);
//Add the new Div
clickNode.appendChild(newDiv);
}
function NI(lpos, event) {
event.preventDefault();
//copy text box
var cI = document.getElementsByClassName('input')[0].cloneNode(true);
cI.value = '';
//find the node that has been clicked
var posAr = lposToAr(lpos);
var clickNode = document.getElementsByTagName('form')[0];
for (var i = 0; i < posAr.length; i++) {
clickNode = clickNode.children;
var skipCount = 0;
for (var j = 0; j < clickNode.length - 1; j++) {
if (clickNode[j].tagName != 'DIV') {
skipCount++;
}
}
clickNode = clickNode[posAr[i] + skipCount - 1];
}
//add the new textbox
clickNode.insertBefore(cI, clickNode.getElementsByClassName('new-input')[0]);
}
document.getElementsByClassName('new-line')[0].addEventListener('click', function(event) {
NL(document.getElementsByClassName('line')[0].innerHTML, event);
});
document.getElementsByClassName('new-nested')[0].addEventListener('click', function(event) {
NN(document.getElementsByClassName('line')[0].innerHTML, event);
});
document.getElementsByClassName('new-input')[0].addEventListener('click', function(event) {
NI(document.getElementsByClassName('line')[0].innerHTML, event);
});
/**
* Add styling to the form to make it look appealing
*/
.form-block {
padding: 5px;
margin: 5px;
border: 1px solid #000;
}
span {
padding-right: 15px;
}
.form-block button, .form-block input {
margin-right: 1em;
}
<!--
DO NOT CHANGE THE CONTENTS OF THIS BLOCK
-->
<form class='myform'>
<div class='form-block'>
<span class='line'>1</span><!--
--><button class='new-line'>New Line</button><!--
--><button class='new-nested'>New Nested Line</button><!--
--><input class='input' type='text' placeholder='Enter Value...'><!--
--><button class='new-input'>Add input</button>
</div>
</form>

onmouseover show only one submenu ( Javascript )

Good day,
trying to make a small menu only with Javascript and got a problem that onmouseover event shows all submenus and not only one.
this is the part of the code that suppose to change style.display to block.
var ul = document.getElementById("navMainId"),
var liDropdown = ul.getElementsByClassName("dropdown");
for (var i = 0; i < liDropdown.length; i++) {
liDropdown[i].style.display = "inline-block";
liDropdown[i].onmouseover = function () {
var ul = document.getElementById("navMainId"),
dropdown = ul.getElementsByClassName("dropdown-content");
for (var i = 0; i < dropdown.length; i++) {
dropdown[i].style.display = "block";
}
}
liDropdown[i].onmouseleave = function () {
var ul = document.getElementById("navMainId"),
dropdown = ul.getElementsByClassName("dropdown-content");
for (var i = 0; i < dropdown.length; i++) {
dropdown[i].style.display = "none";
}
}
}
How can i change the code to make it work ?
here is whole code on Fiddle ( ssry it is a mess ) : https://jsfiddle.net/apvsnzt5/1/
I've updated the fiddle:
https://jsfiddle.net/apvsnzt5/3/
All you needed to do was change
dropdown = ul.getElementsByClassName("dropdown-content");
to
dropdown = this.getElementsByClassName("dropdown-content");
So that it targets the "this" (being the LI you are hovered over) rather than finding the "dropdown-content" inside the UL.
Also do it on the onmouseleave.
Seems you have incorrect reference to container when mouser over. You need concrete content based on your mosue position.
var dropdown = this.getElementsByClassName("dropdown-content");
try updated fiddle
add the following to your css part
.dropdown-content{
display:none ! important;
}
a:hover+.dropdown-content{
display:block ! important;
}
it will works fine.
var menuCont = document.createElement("div");
document.body.appendChild(menuCont);
var ulMain = document.createElement("ul");
menuCont.appendChild(ulMain);
ulMain.className = "navMain";
ulMain.id = "navMainId";
/****** MENU ******/
// Software
var liSoftware = document.createElement("li");
liSoftware.className = "menu dropdown";
ulMain.appendChild(liSoftware);
var aSoftware = document.createElement("a");
aSoftware.className = "menuName dropbtn";
aSoftware.href = "#";
aSoftware.textContent = "Test1";
liSoftware.appendChild(aSoftware);
// GeCoSoft
var liGeco = document.createElement("li");
liGeco.className = "menu dropdown";
ulMain.appendChild(liGeco);
var aGeco = document.createElement("a");
aGeco.className = "menuName dropbtn";
aGeco.href = "#";
aGeco.textContent = "Test2";
liGeco.appendChild(aGeco);
/******* Submenu *******/
// Software Sub
var divSubSoft = document.createElement("div");
divSubSoft.className = "dropdown-content";
liSoftware.appendChild(divSubSoft);
var aSub1 = document.createElement("a"),
aSub2 = document.createElement("a");
aSub1.className = "menuSubName";
aSub1.textContent = "SubMenu1";
aSub1.href = "#";
aSub2.className = "menuSubName";
aSub2.textContent = "SubMenu2";
aSub2.href = "#";
divSubSoft.appendChild(aSub1);
divSubSoft.appendChild(aSub2);
// Gecosoft Sub
var divSubGeco = document.createElement("div");
divSubGeco.className = "dropdown-content";
liGeco.appendChild(divSubGeco);
var aSub3 = document.createElement("a"),
aSub4 = document.createElement("a");
aSub3.className = "menuSubName";
aSub3.textContent = "Submenu3";
aSub3.href = "#";
aSub4.className = "menuSubName";
aSub4.textContent = "SubMenu4"
aSub4.href = "#";
divSubGeco.appendChild(aSub3);
divSubGeco.appendChild(aSub4);
/****** MENU STYLE ******/
var i = "";
ulMain.style.listStyleType = "none";
ulMain.style.margin = "0px";
ulMain.style.padding = "0px";
ulMain.style.overflow = "hidden";
ulMain.style.backgroundColor = "rgb(232, 225, 225)";
var ul = document.getElementById("navMainId"),
li = ul.getElementsByTagName("li");
for (var i = 0; i < li.length; i++) {
li[i].style.cssFloat = "left";
}
var a = ul.getElementsByTagName("a");
for (var i = 0; i < a.length; i++) {
a[i].style.display = "inline-block";
a[i].style.color = "black";
a[i].style.textAlign = "center";
a[i].style.padding = "14px 16px";
a[i].style.textDecoration = "none";
a[i].onmouseover = function () {
this.style.backgroundColor = "rgb(174, 170, 170)";
}
a[i].onmouseleave = function () {
this.style.backgroundColor = "rgb(232, 225, 225)";
}
}
/************ Dont know what to do here **************/
var liDropdown = ul.getElementsByClassName("dropdown");
for (var i = 0; i < liDropdown.length; i++) {
liDropdown[i].style.display = "inline-block";
liDropdown[i].onmouseover = function () {
var ul = document.getElementById("navMainId"),
dropdown = ul.getElementsByClassName("dropdown-content");
for (var i = 0; i < dropdown.length; i++) {
dropdown[i].style.display = "block";
}
}
liDropdown[i].onmouseleave = function () {
var ul = document.getElementById("navMainId"),
dropdown = ul.getElementsByClassName("dropdown-content");
for (var i = 0; i < dropdown.length; i++) {
dropdown[i].style.display = "none";
}
}
}
var divDropCont = ul.getElementsByClassName("dropdown-content");
for (var i = 0; i < divDropCont.length; i++) {
divDropCont[i].style.display = "none";
divDropCont[i].style.position = "absolute";
divDropCont[i].style.backgroundColor = "#f9f9f9";
divDropCont[i].style.minWidth = "160px";
divDropCont[i].style.boxShadow = "0px 8px 16px 0px rgba(0,0,0,0.2)";
}
var aDropCont = ul.getElementsByClassName("menuSubName");
for (var i = 0; i < aDropCont.length; i++) {
aDropCont[i].style.color = "black";
aDropCont[i].style.padding = "12px 16px";
aDropCont[i].style.textDecoration = "none";
aDropCont[i].style.display = "block";
aDropCont[i].style.textAlign = "left";
aDropCont[i].onmouseover = function () {
this.style.backgroundColor = "rgb(174, 170, 170)";
}
aDropCont[i].onmouseleave = function () {
this.style.backgroundColor = "rgb(249, 249, 249)";
}
}
.dropdown-content{
display:none ! important;
}
a:hover+.dropdown-content{
display:block ! important;
}

Categories