Javascript To Toggle Multiple Buttons - javascript

I have some Javascript code that targets multiple buttons. When clicked, the content should appear, which it does. However, i'm struggling to create the code that when the buttons are clicked again, the content is hidden.
I've included the Javascript, content and css for the elements i want to be toggled. Cheers.
Note: Code has to be in Javascript
function openTab(click, openTab) {
var i, content, link;
content = document.getElementsByClassName("content");
for (i = 0; i < content.length; i++) {
content[i].style.display = "none";
}
links = document.getElementsByClassName("links");
for (i = 0; i < links.length; i++) {
links[i].className = links[i].className.replace(" active", "");
}
document.getElementById(openTab).style.display = "block";
click.currentTarget.className += " active";
}
.content {
font-family: 'Lato';
max-width: 100%;
font-size: 20px;
letter-spacing: 4px;
color: #e8eaed;
display: none;
border-top: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<section class = "Container">
<div class="tabs">
<button class="link" onclick="openTab(event, 'About')">About</button>
<button class="link" onclick="openTab(event, 'Hire')">Why You Should Hire Me</button>
<button class="link" onclick="openTab(event, 'Contact')">Contact</button>
</div>
</section>
<section class="Container2">
<div id="About" class="content">About</div>
<div id="Hire" class="content">Hire</div>
<div id="Contact" class="content">Contact</div>
</section>

Declare a variable which represents whether the elements are hidden or not. Also, you could try to use classList to add/remove classes from elements with multiple class names, rather than className string manipulation, if at all possible.
You can use classList.toggle to easily switch classes:
let hidden = false;
function openTab(click, openTabId) {
document.querySelectorAll('.content').forEach(
content => content.style.display = hidden ? 'block' : 'none'
);
document.querySelectorAll('.links').forEach(
link => link.classList.toggle('active')
);
document.getElementById(openTabId).style.display = "block";
click.currentTarget.classList.toggle('active');
hidden = !hidden;
}
Better yet, encapsulate the hidden variable in openTab, since it's not useful in the outer scope:
const openTab = (() => {
let hidden = false;
return (click, openTabId) => {
document.querySelectorAll('.content').forEach(
content => content.style.display = hidden ? 'block' : 'none'
);
document.querySelectorAll('.links').forEach(link => {
if (hidden) link.classList.add('active');
else link.classList.remove('active');
});
document.getElementById(openTabId).style.display = "block";
click.currentTarget.classList.toggle('active');
hidden = !hidden;
}
})();

Related

How do I get the ViewButton to not copy the old note.value

//javascript, this is where I'm having the issue
const form = document.querySelector("#Form");
const note = document.querySelector("#Note");
const table = document.querySelector("#noteTable");
const count = 0;
form.addEventListener("submit", (e) => {
e.preventDefault();
if (note.value !== '') {
const btn = document.createElement("button");
btn.innerHTML = "View Details";
const row = table.insertRow();
const noteRow = row.insertCell();
const viewD = row.insertCell();
noteRow.innerHTML = note.value;
viewD.append(btn);
model.append(note.value);
note.value = "";
btn.addEventListener("click", () => {
model.classList.add("show");
});
const close = document.querySelector("#close");
close.addEventListener("click", () => {
model.classList.remove("show");
});
} else {
alert("Write a note!");
}
});
css button {
color: black;
background-color: green;
}
body {
background-color: rgb(182, 215, 227);
min-height: 100vh;
margin: 0;
}
.model-container {
background-color: rgba(245, 222, 179, 0.38);
position: fixed;
display: flex;
justify-content: center;
align-items: center;
top: 0;
left: 0;
height: 100vh;
width: 100vh;
opacity: 0;
pointer-events: none;
}
.model {
background-color: white;
}
.model-container.show {
pointer-events: auto;
opacity: 1;
}
.open:hover {
cursor: pointer;
color: white;
}
td {
display: block;
}
<h2>NOTE TAKER</h2>
<h6>Add A New Note:</h6>
<form id="Form" action="#">
<label class="ntag" for="note">Note:</label>
<input class="ntag" name="note" id="Note" type="text" placeholder="Write a note">
<button id="Add">Add Note</button>
</form>
<div class="theTable">
<table id="noteTable">
<tr id="Headers" class="headers">
<th></th>
</tr>
</table>
</div>
<div class="model-container" id="model">
<div class="model">
<button class="close" id="close">Close Me</button>
</div>
</div>
I'm not sure why but the notes repeat in the model-container, after you make another note the first one is still there with the second one right after it.
I thought that it could be the placement, so i put it in the btn function, but it duplicated as well; also sorry for how ugly this is, I'm just focused on the JavaScript
If you inspect the source after adding a few notes, you'll notice that it looks like this, assuming I added notes "one", "two" and "three":
It's putting it there because of this line of javascript:
model.append(note.value);
The .append() method doesn't wipe out anything in the <div id="model">, it just adds on to whatever is in there by dumping it after the button or dumping after any existing text.
To avoid erasing the "Close Me" button you'll probably want another div specifically for the text so that instead of using .append() you can just set the .textContent of the element each time. This would be destructive in a way that you wouldn't want to do this on the parent element, because it would wipe out the button. .append() is what is retaining the previous stuff when you click "View Detail."
<div class="model-container" id="model">
<div class="model">
<button class="close" id="close">Close Me</button>
</div>
<div id="txtDetails"><div>
</div>
So instead of using .append() just set the text of <div id="txtDetails"> to what you want it to say by setting the .textContent.
I also added a "data-text" attribute to the button on creation so it would be easier to fish out the text instead of navigating the parent elements and across elements.
Finally, on the click listener event I made it take whatever is stored in the "data-text" attribute and place that into <div id="txtDetails"> so that each "View Details" click would only show what is relevant for that particular note. This method is destructive in that it wipes out and replaces anything in <div id="txtDetails"> with each click but leaves the button in the modal alone.
const form = document.querySelector("#Form");
const note = document.querySelector("#Note");
const table = document.querySelector("#noteTable");
const count = 0;
form.addEventListener("submit", (e) => {
e.preventDefault();
if(note.value !== '')
{
const btn = document.createElement("button");
btn.innerHTML = "View Details";
btn.setAttribute('data-text', note.value);
const row = table.insertRow();
const noteRow = row.insertCell();
const viewD = row.insertCell();
noteRow.innerHTML = note.value;
viewD.append(btn);
note.value = "";
btn.addEventListener("click", () => {
document.getElementById('txtDetails').textContent = btn.getAttribute('data-text');
model.classList.add("show");
});
const close = document.querySelector("#close");
close.addEventListener("click", () => {
model.classList.remove("show");
});
}
else{
alert("Write a note!");
}
});
https://jsfiddle.net/tnqp8L0x/

Javascript OnClick function for multiple Div Class elements that reveal a block of text when clicked on

I am trying to enable an Onclick event to fire up when any of my div elements that match the div class "Clicker" is clicked on.
However iI am not so good with JavaScript and do not know how to go about this.
I was successful when I used the "document.getElementById" when my divs were made into Id and not "Class" elements but only one could function.
see my code below;
document.getElementsByClassName("Clicker").addEventListener("click", function () {
var infoBox = document.getElementsByClassName("thumbnail-reveal-txt");
if (infoBox.style.display == "none") {
infoBox.style.display = "block";
} else {
infoBox.style.display = "none";
}
})
<div class="thumbnail-reveal-txt" style="position: absolute; display: none;">
<div class="thumbnail-reveal-txt" style="position: absolute; display: none;">
<div class="thumbnail-reveal-txt" style="position: absolute; display: none;">
You can use querySelector and querySelectorAll
document.querySelector(".Clicker").addEventListener("click", function () {
const infoBox = document.querySelectorAll(".thumbnail-reveal-txt");
infoBox.forEach(i => {
if (i.style.display == "none") {
i.style.display = "block";
} else {
i.style.display = "none";
}
})
})
<button class="Clicker">click</button>
<div class="thumbnail-reveal-txt" style="position: absolute; display: none;">1</div>
<div class="thumbnail-reveal-txt" style="position: absolute; display: none;">2</div>
<div class="thumbnail-reveal-txt" style="position: absolute; display: none;">3</div>
When you use getElementsByClassName, you're not specifying wich of the elements you are trying to change the className property.
For that, you can use a loop
document.getElementsByClassName("Clicker").addEventListener("click", function () {
var infoBox = document.getElementsByClassName("thumbnail-reveal-txt");
for (let i = 0; i < infoBox.length; i +=1) {
if (infoBox[i].style.display == "none") {
infoBox[i].style.display = "block";
} else {
infoBox[i].style.display = "none";
}
}
})

How to add eventlistener to dynamically created divs

How to add event delegation to dynamically created divs, to change property of the target div? I've tried several suggestions that I found for event delegation but none of them work. I think I'm making some mistakes but I don't know how to fix.
I am trying to develop a file thumbnail list interface with HTML and JavaScript. I made a method that draws thumbnails dynamically from an Array. And now I want to add some functions to manipulate the thumbnails, ex. changing border color of the item(div) when it is clicked.
First I tried loop-method to add event listeners to the divs, but it didn't work well. And now I learned that event delegation is better way to add event listeners to dynamically created elements. But the problem is that though I'v tried codes but they didn't work at all.
I think I am making some mistakes or mis-using methods but I don't know what is the problem.
JavaScript
function drawThumbnails(area, list){
var j
var createdList = []
for (j=0; j<list.length; j++){
var thmb = document.getElementById("fileThumb");
var name = document.getElementById("itemName");
var date = document.getElementById("itemDate");
var thmbimg = document.getElementById("fileThumbImage");
var thmbicon = document.getElementById("file_icon_thumb");
name.innerHTML=list[j][0];
date.innerHTML=list[j][1];
if (list[j][2] == "folder"){
thmbimg.src = "thmb_folder.png";
thmbicon.style.display = "none";
}
else {
if (list[j][2] == "img"){
thmbimg.src=getthmbimgsample();
}
else{
thmbimg.src = getThmbimg(list[j][2]);
}
thmbicon.style.display = "block";
thmbicon.src = getThmbicon(list[j][2]);
}
var cln = thmb.cloneNode(true);
cln.style.display = "block";
document.getElementById(area).append(cln);
createdList.push(cln);
}
thmbLists.push(createdList);
}
drawThumbnails("folderArea", folders);
drawThumbnails("fileArea", files);
document.getElementById("folderArea").addEventListener('click',function(e){
if(e.target && e.target.className == "fileThumb"){
e.target.style.borderColor = "#408CFF";
}
});
HTML
<body>
<div class = "contentArea" id="contentArea">
<div class = "thumbArea" id="folderArea">
<div class = "fileThumb" id="fileThumb">
<img src="icon_thumb_folder.png" class="fileThumb_normal" id="fileThumbImage">
<div class="fileName">
<img src="icon_thumb_file.png" style="width: 20px;" id="file_icon_thumb">
<div class="fileNameLine" id = "itemName">File/FolderName</div>
<div class="fileNameDate" id="itemDate">Date</div>
</div>
</div>
</div>
<div class = "contentAreaSectionHeader">
<input type="checkbox" id="chTest2" name="chTest2">
<label for="chTest2"><span>Files</span></label>
</div>
<div class = "thumbArea" id="fileArea">
</div>
</body>
CSS
.fileThumb{
width: 213px;
height: 183px;
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #EEEEEE;
text-align: center;
position: relative;
float:left;
margin: 18px;
display: none;
overflow: hidden;
}

show/hide elements and switch between them js

I have two elements that are hidden. When button a is clicked, I would like div a to show. When button b is clicked, I would like div a to close and div b to show.
However, if button a is clicked a second time after being shown, I would like it to hide the div again. Same with button b.
Update:
I was able to get the buttons to toggle properly.
However, upon initial loading, I want them to be hidden, or not visible until the button is clicked.
The following is my current javascript
function openFamily(evt, famName) {
var i, x, y, tablinks;
x = document.getElementsByClassName("family");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
tablinks = document.getElementsByClassName("familytablink");
for (i = 0; i < x.length; i++)
document.getElementById(famName).style.display = "block";
}
I have a CSS element:
.container{
display: none;
}
HTML:
<div>
<div>
<button class="familytablink" onclick="openFamily(event,'zep')">Zephaniah</button>
<button class="familytablink" onclick="openFamily(event,'anna')">Anna</button>
</div>
<div id="zep" class="container mainp-2 family">
filler text
</div>
<div id="anna" class="container mainp-2 family">
filler text
</div>
</div>
Here's an exemple of how you can achieve that
var toggleDivById = function (id) {
var div = document.getElementById(id);
if (div.classList.contains('active')) {
return div.classList.remove('active');
}
div.classList.add('active');
}
var handleToggleClick = function (event) {
var targetId = event.target.dataset.target;
toggleDivById(targetId);
}
document.querySelectorAll('.toggle')
.forEach(function(toggle) {
toggle.addEventListener('click', handleToggleClick)
})
.toggable {
width: 50px;
height: 50px;
background-color: crimson;
border: 2px solid tomato;
visibility: hidden;
transition: all 100ms ease-out;
border-radius: 5px;
box-shadow: 1px 1px 2px indianred;
}
.toggable.active {
visibility: visible
}
<button data-target="a" class="toggle">A</button>
<button data-target="b" class="toggle">B</button>
<hr/>
<div id="a" class="toggable">A</div>
<div id="b" class="toggable">B</div>
In jQuery:
<script type="application/javascript">
$(document).ready(function(){
$("#button1").click(function(){
$("diva").show();
});
$("#button2").click(function(){
$("diva").hide();
$("divb").show();
});
});
</script>
In JS:
<script type="application/javascript">
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
You can use hide and show function in Jquery and use it when a button is clicked something like this :
like
$("selector").click(function(){
$("divid").hide();
$("divid").show();
})

Rearrange HTML Focused Tab's Row on button click

I'm porting a program from XAML/C# to HTML/CSS/JavaScript.
I have tabbed sections which rearrange the focused tab's row to the bottom when clicked. This is automatically performed by the TabControl in XAML.
XAML/C#
General Focused
Video Focused
HTML/CSS/JavaScript
How can I do the same with JavaScript?
I'm using this script https://www.w3schools.com/w3css/w3css_tabulators.asp
// Display Tab Section
function OpenTab(tabName) {
var i;
var x = document.getElementsByClassName("tabSection");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
document.getElementById(tabName).style.display = "block";
}
.btnTab {
width: 33.33%;
display: block;
float: left;
background: #020f31;
color: #fff;
padding: 0.2em;
border-top: 1px solid #0080cb;
border-right: 1px solid #0080cb;
border-bottom: none;
border-left: 1px solid #0080cb;
cursor: pointer;
}
<!-- Tabs -->
<div id="sectionTabs">
<button class="btnTab" onclick="OpenTab('General')">General</button>
<button class="btnTab" onclick="OpenTab('Stream')">Stream</button>
<button class="btnTab" onclick="OpenTab('Display')">Display</button>
<button class="btnTab" onclick="OpenTab('Video')">Video</button>
<button class="btnTab" onclick="OpenTab('Audio')">Audio</button>
<button class="btnTab" onclick="OpenTab('Subtitles')">Subtitles</button>
</div>
<!-- Sections -->
<div id="General" class="tabSection">
General ...
</div>
<div id="Stream" class="tabSection" style="display:none">
Stream ...
</div>
<div id="Display" class="tabSection" style="display:none">
Display ...
</div>
<div id="Video" class="tabSection" style="display:none">
Video ...
</div>
<div id="Audio" class="tabSection" style="display:none">
Audio ...
</div>
<div id="Subtitles" class="tabSection" style="display:none">
Subtitles ...
</div>
Fiddle Link
Well if you can change markup a little bit like wrapping the first row and second row of the buttons on different div...
Also try to avoid inline javascript and use data-attributes here
Steps:
create a new array instance from iterable object y usinf Array.from
add a click event on all the buttons using addEventListener
hide all the elements containing tabSection class and also remove active class from all the buttons using for loop.
get the data-tab value from clicked button and set display:block to the respected tab and also add active class to the current button.
now for switching the .first and .second div up and down use insertBefore inside the if condition to compare the index of the clicked button
var x = document.getElementsByClassName("tabSection");
var y = document.getElementsByClassName("btnTab");;
var a = document.querySelector(".first");
var b = document.querySelector(".second")
var p = document.getElementById("sectionTabs");
Array.from(y).forEach(function(elem, index) {
elem.addEventListener("click", function() {
for (var i = 0; i < x.length; i++) {
x[i].style.display = "none";
y[i].classList.remove("active");
}
var tab = this.getAttribute("data-tab");
document.getElementById(tab).style.display = "block";
this.classList.add("active");
if (index < 3) {
p.insertBefore(b, p.childNodes[0])
} else {
p.insertBefore(a, p.childNodes[0])
}
})
})
.btnTab {
width: 33.33%;
display: block;
float: left;
background: #020f31;
color: #fff;
padding: 0.2em;
border-top: 1px solid #0080cb;
border-right: 1px solid #0080cb;
border-bottom: none;
border-left: 1px solid #0080cb;
cursor: pointer;
outline: none;
}
.btnTab.active {
background: red;
}
<!-- Tabs -->
<div id="sectionTabs">
<div class="first">
<button class="btnTab" data-tab="General">General</button>
<button class="btnTab" data-tab="Stream">Stream</button>
<button class="btnTab" data-tab="Display">Display</button>
</div>
<div class="second">
<button class="btnTab active" data-tab="Video">Video</button>
<button class="btnTab" data-tab="Audio">Audio</button>
<button class="btnTab" data-tab="Subtitles">Subtitles</button>
</div>
</div>
<!-- Sections -->
<div id="General" class="tabSection" style="display:none">
General ...
</div>
<div id="Stream" class="tabSection" style="display:none">
Stream ...
</div>
<div id="Display" class="tabSection" style="display:none">
Display ...
</div>
<div id="Video" class="tabSection">
Video ...
</div>
<div id="Audio" class="tabSection" style="display:none">
Audio ...
</div>
<div id="Subtitles" class="tabSection" style="display:none">
Subtitles ...
</div>
Reference Link:
Array.from
forEach()
element.addEventListener
element.classList
element.style
node.insertBefore
This can be achieved by adding a bit more code to OpenTab().
First of all, to check whether a button in the top row or bottom row was pressed, you may add classes row1 to the first row of buttons and row2 to the second row. Then, you can check which button was pressed in OpenTab() by passing in this as an additional parameter: onclick="OpenTab(this, 'General').
With these changes to HTML, the javascript can be changed to change the button pressed into account. In the code below, each if statement checks that the current button is in a particular row with elem.classList.contains("rowX") and that the row is the top row with parent.firstElementChild.classList.contains("rowX"). It then loops through the number of tabs in the row (amount of tabs can vary) and places them in the beginning of the #sectionTabs div.
function OpenTab(elem, tabName) { // Note that `elem` is where `this` is passed
// Your original code
var i;
var x = document.getElementsByClassName("tabSection");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
document.getElementById(tabName).style.display = "block";
// Additional code
row1_elem = document.getElementsByClassName("row1"); // initially top row
row2_elem = document.getElementsByClassName("row2"); // initially bottom row
parent = document.getElementById("sectionTabs");
// check that button in top row was clicked
if (elem.classList.contains("row1") == 1 && parent.firstElementChild.classList.contains("row1") == 1) {
// move elements from bottom row up
for (var j = 0; j < row2_elem.length; j++) {
parent.insertBefore(row2_elem[row2_elem.length-1], parent.firstChild);
}
// check that button in top row was clicked
} else if (elem.classList.contains("row2") == 1 && parent.firstElementChild.classList.contains("row2") == 1) {
// move elements from bottom row up
for (var j = 0; j < row1_elem.length; j++) {
parent.insertBefore(row1_elem[row1_elem.length-1], parent.firstChild);
}
}
}
A jsfiddle is also available:
https://jsfiddle.net/o687eLyb/
Note that you could also wrap the rows into separate divs with IDs rowX and use slightly different logic to check which row was pressed; however, this answer has the benefit that it keeps HTML structure the same.

Categories