tabs don't work properly - javascript

I created tabs on JS and my script decided to deny working.
I click on tabs - they don't work and content also is not hidden.
Chrome shows NO bugs. Code should work without doubts but it seems an error somewere. All the classes such as 'hide', 'show' are created on external style.css file.
Please, help !!
var tab;
var content;
window.onload = function() {
content = document.querySelector('.content');
tab = document.querySelector('.tab');
hideTabsContent(1);
}
function hideTabsContent(a) {
for (var i = a; i < content.length; i++) {
content[i].classList.remove('show');
content[i].classList.add("hide");
tab[i].classList.remove('active');
}
}
document.querySelector('.container').onclick = function(event) {
var target = event.target;
if (target.className == 'tab') {
for (var i = 0; i < tab.length; i++) {
if (target == tab[i]) {
showTabsContent(i);
break;
}
}
}
}
function showTabsContent(b) {
if (content[b].classList.contains('hide')) {
hideTabsContent(0);
tab[b].classList.add('active');
content[b].classList.remove('hide');
content[b].classList.add('show');
}
}
.tab {
cursor: pointer;
}
.active {
color: white;
background-color: green;
}
.show {
display: block;
}
.hide {
display: none;
}
<div class="container">
<div class="tab active">Summer</div>
<div class="tab">Autumn</div>
<div class="tab">Winter</div>
<div class="content">
<img src="img/pic-1.jpg">
<img src="img/pic-2.jpg">
<img src="img/pic-3.jpg">
</div>
<div class="content">
<img src="img/pic-4.jpg">
<img src="img/pic-5.jpg">
<img src="img/pic-6.jpg">
</div>
<div class="content">
<img src="img/pic-7.jpg">
<img src="img/pic-8.jpg">
<img src="img/pic-9.jpg">
</div>
</div>

Use querySelectorAll to return an array of elements or it returns just the first found element.
window.onload=function() {
content=document.querySelectorAll('.content');
tab=document.querySelectorAll('.tab');
hideTabsContent(1);
}

Change the selection from querySelctor() to querySelectorAll() working example is below
var tab;
var content;
window.onload = function() {
content = document.querySelectorAll('.content');
tab = document.querySelectorAll('.tab');
hideTabsContent(1);
}
function hideTabsContent(a) {
for (var i = a; i < content.length; i++) {
content[i].classList.remove('show');
content[i].classList.add("hide");
tab[i].classList.remove('active');
}
}
document.querySelector('.container').onclick = function(event) {
var target = event.target;
if (target.className == 'tab') {
for (var i = 0; i < tab.length; i++) {
if (target == tab[i]) {
showTabsContent(i);
break;
}
}
}
}
function showTabsContent(b) {
if (content[b].classList.contains('hide')) {
hideTabsContent(0);
tab[b].classList.add('active');
content[b].classList.remove('hide');
content[b].classList.add('show');
}
}
.tab {
cursor: pointer;
}
.active {
color: white;
background-color: green;
}
.show {
display: block;
}
.hide {
display: none;
}
<div class="container">
<div class="tab active">Summer</div>
<div class="tab">Autumn</div>
<div class="tab">Winter</div>
<div class="content">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<div class="content">
<span>4</span>
<span>5</span>
<span>6</span>
</div>
<div class="content">
<span>7</span>
<span>8</span>
<span>9</span>
</div>
</div>

Related

Nothing seems to happen when I click on any of my tabs

I have three tabs, but when I click on any of them, nothing happens and there is no error in the console. What is wrong?
When I click on any of .tabs-nav-item nothing happens.
function initTab(elem) {
document.addEventListener("click", function(e) {
if (!e.target.matches(elem + " .tabs-nav-item")) return;
else {
if (!e.target.classList.contains("active")) {
findActiveElementAndRemoveIt(elem + " .tabs-nav-item");
findActiveElementAndRemoveIt(elem + " .tab-content-item");
e.target.classList.add("active");
setTimeout(function() {
var panel = document.querySelectorAll(
elem + " .tab-content-item" + e.target.dataset.name
);
Array.prototype.forEach.call(panel, function(el) {
el.classList.add("active");
ckj;
});
}, 200);
}
}
});
}
function findActiveElementAndRemoveIt(elem) {
var elementList = document.querySelectorAll(elem);
Array.prototype.forEach.call(elementList, function(e) {
e.classList.remove("active");
});
}
initTab(".tabs");
<div class="tabs">
<div class="tabs-nav">
<p class="tabs-nav-item active" data-name="profile">Profile</p>
<p class="tabs-nav-item" data-name="messages">Messages</p>
<p class="tabs-nav-item" data-name="settings">Settings</p>
</div>
<div class="tabs-content">
<div class="profile active tab-content-item">
<h3>Lorem</h3>
</div>
<div class="tab-content-item messages">
<h3>ipsum </h3>
</div>
<div class="tab-content-item settings">
<h3>sit amet.</h3>
</div>
</div>
</div>
I think that you have problem in the selector inside setTimeout function.
I have made it work using data attributes
function initTab(elem) {
document.addEventListener("click", function (e) {
if (!e.target.matches(elem + " .tabs-nav-item")) return;
else {
if (!e.target.classList.contains("active")) {
findActiveElementAndRemoveIt(elem + " .tabs-nav-item");
findActiveElementAndRemoveIt(elem + " .tab-content-item");
e.target.classList.add("active")
setTimeout(function () {
var panel = document.querySelectorAll(".tab-content-item[data-name=" + e.target.dataset.name + "]");
Array.prototype.forEach.call(panel, function (el) {
el.classList.add("active");
});
}, 200);
}
}
});
}
function findActiveElementAndRemoveIt(elem) {
var elementList = document.querySelectorAll(elem);
Array.prototype.forEach.call(elementList, function (e) {
e.classList.remove("active");
});
}
initTab(".tabs");
.tabs-nav {
display: flex;
gap: 16px;
}
.tabs-nav-item {
cursor: pointer;
}
.tabs-nav .active {
font-weight: bold;
}
.tabs-content .tab-content-item {
display: none;
}
.tabs-content .active {
display: block;
}
<div class="tabs">
<div class="tabs-nav">
<p class="tabs-nav-item active" data-name="profile">Profile</p>
<p class="tabs-nav-item" data-name="messages">Messages</p>
<p class="tabs-nav-item" data-name="settings">Settings</p>
</div>
<div class="tabs-content">
<div class="active tab-content-item" data-name="profile">
<h3>Lorem</h3>
</div>
<div class="tab-content-item" data-name="messages">
<h3>ipsum </h3>
</div>
<div class="tab-content-item" data-name="settings">
<h3>sit amet.</h3>
</div>
</div>
</div>
I hope that this will help is you didn't solve the issue yet.
Just Run the code snippet to see the result.

Show child elements if parent is visible

I'm trying to have my form show child elements if the parent is visible and I keep getting an "undefined" error with my child element, even though I have it defined. I'm trying to have set this up where:
Q1: Checked responses will show parent elements (divs).
Q2: Depending on this response, it'll show child elements (divs).
Is there a way to do this?
//Next Tab
function next() {
var formTabOne = document.getElementById("stepOne");
formTabOne.classList.add("formTrans");
formTabOne.addEventListener("transitionend", function({
target
}) {
if (target === formTabOne) {
target.classList.add("hidden");
target.classList.remove("formTrans");
document.getElementById("stepTwo").classList.remove("hidden");
}
})
}
//Prev Tab
function prev() {
var formTabTwo = document.getElementById("stepTwo");
formTabTwo.classList.add("formTrans");
formTabTwo.addEventListener("transitionend", function({
target
}) {
if (target === formTabTwo) {
target.classList.add("hidden");
target.classList.remove("formTrans");
document.getElementById("stepOne").classList.remove("hidden");
}
})
}
function process() {
var form = document.myForm;
var biz = document.getElementById("biz");
var career = document.getElementById("career");
var change = document.getElementById("change");
var eq = document.getElementById("eq");
var empathy = document.getElementById("empathy");
var pm = document.getElementById("pm");
var bizMgr = document.getElementsByClassName("bizMgr");
var bizEE = document.getElementsByClassName("bizEE");
//Q1 - Topics
document.querySelectorAll("#chkTopic input").forEach((el) => {
const contentID = el.id.replace("chk", "").toLowerCase()
document.getElementById(contentID).style.display = el.checked ? "block" : "none";
});
//Q2 - Employee Type
var q2value = "";
for (var i = 0; i < form.q2.length; i++) {
var answer = form.q2[i];
if (answer.checked) {
q2value = answer.value;
}
}
if (q2value == "1") {
if (biz.style.display = "block") {
bizMgr.style.display = "block";
bizEE.style.display = "block";
}
} else {
if (biz.style.display = "block") {
document.getElementsByClassName("bizEE").style.display = "block";
}
}
}
html {
scroll-behavior: smooth;
}
#formWrapper {
background-color: #eaeaea;
padding: 20px;
margin-bottom: 40px;
min-height: 300px;
}
#myForm {
width: 70%;
min-height: 280px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
border: 1px solid #dedede;
box-sizing: border-box;
}
.formStep {
opacity: 1;
background: #fff;
}
.formTrans {
visibility: hidden;
opacity: 0;
transition: visibility 0s 200ms, opacity 200ms linear;
}
.hidden {
display: none;
}
#biz, #career, #change, #eq, #empathy, #pm, #pd {
display: none;
width: 100%;
min-height: 200px;
box-sizing: border-box;
margin-bottom: 30px;
border: 1px solid #000;
}
.bizMgr, .bizEE, .careerMgr, .careerEE, .changeMgr, .changeEE, .eqMgr, .eqEE, .empathyMgr, .empathyEE, .pmMgr, .pmEE, .pdMgr, .pdEE {
display: none;
}
<form name="myForm" id="myForm">
<input type="button" value="Skip This" onclick="formSkip();">
<br><br>
<!--Step 1-->
<div id="stepOne" class="formStep">
<b>Select the topic(s) you're interested in:</b><br>
<div id="chkTopic">
<input id="chkBiz" type="checkbox" value="1"><label for="chkBiz">Business Structure/Acumen</label><br>
<input id="chkCareer" type="checkbox" value="2"><label for="chkCareer">Career Development</label><br>
<input id="chkChange" type="checkbox" value="3"><label for="chkChange">Change</label><br>
<input id="chkEQ" type="checkbox" value="4"><label for="chkEQ">Emotional Intelligence</label><br>
<input id="chkEmpathy" type="checkbox" value="5"><label for="chkEmpathy">Empathy</label><br>
<input id="chkPM" type="checkbox" value="6"><label for="chkPM">Performance Management</label><br>
</div>
<br>
<button type="button" id="btnStepOne" onclick="next();">Next</button>
</div>
<!--Step 2-->
<div id="stepTwo" class="formStep hidden">
<b>Are you a people leader?</b><br>
<input type="radio" name="q2" value="0">No<br>
<input type="radio" name="q2" value="1">Yes<br>
<br>
<button type="button" id="btnStepTwo" onclick="prev();">Previous</button>
<input type="button" value="Show Results" onclick="process();">
<input type="reset" value="Start Over" onclick="formReset();">
</div>
</form>
<div id="results">
<div id="biz">
Business Structure/Acumen
<div class="bizMgr">Manager Content</div>
<div class="bizEE">Employee Content</div>
</div>
<div id="career">
Career Development
<div class="careerMgr">Manager Content</div>
<div class="careerEE">Employee Content</div>
</div>
<div id="change">
Change
<div class="changeMgr">Manager Content</div>
<div class="changeEE">Employee Content</div>
</div>
<div id="eq">
Emotional Intelligence
<div class="eqMgr">Manager Content</div>
<div class="eqEE">Employee Content</div>
</div>
<div id="empathy">
Empathy
<div class="empathyMgr">Manager Content</div>
<div class="empathyEE">Employee Content</div>
</div>
<div id="pm">
Performance Management
<div class="pmMgr">Manager Content</div>
<div class="pmEE">Employee Content</div>
</div>
</div>
.getElementsByClassName returns a collection, bizMgr and bizEE are both collections. You have to iterate the collections and set each element to style.display = 'block'. You can't just call xxx.style.display on a javascript collection. You would want to change your code like the following:
if (q2value == "1") {
if (biz.style.display = "block") {
//bizMgr.style.display = "block"; -NO
//bizEE.style.display = "block"; -NO
for(let i = 0; i < bizMgr.length; i++){
bizMgr[i].style.display = "block";
}
for(let j = 0; j < bizEE.length; j++){
bizEE[j].style.display = "block";
}
}
} else {
if (biz.style.display = "block") {
//document.getElementsByClassName("bizEE").style.display = "block"; -NO
for(let j = 0; j < bizEE.length; j++){
bizEE[j].style.display = "block";
}
}
}

Only allow the user to select a maximum of three blocks

I have a piece of code that adds an event listener to a number of buttons, when the user clicks a button a class is applied to the button container. How can I restrict this so the user can only select a maximum of three buttons. The code below is working to a point, when you get to three you cannot deselect. Can anyone help me achieve
var blocks = document.querySelectorAll(".block");
var btn = document.querySelectorAll("button");
var total = 0;
for (let i = 0; i < btn.length; i++) {
btn[i].addEventListener("click", function() {
if (total < 3 && blocks[i].classList.contains("active")) {
blocks[i].classList.remove("active");
total--;
} else if (total < 3 && !blocks[i].classList.contains("active")) {
blocks[i].classList.add("active");
total++;
}
});
}
.container{
display:flex;
}
.block{
padding: 50px;
border:1px solid;
max-width:
}
.block.active{
background:grey;
}
<div class="container">
<div class="block">
<button>click</button>
</div>
<div class="block">
<button>click</button>
</div>
<div class="block">
<button>click</button>
</div>
<div class="block">
<button>click</button>
</div>
</div>
this.
You simply need to remove this condition total < 3 && from your first if. The number of selected items is irrelevant if the element is already selected. You just want to de-select it.
var blocks = document.querySelectorAll(".block");
var btn = document.querySelectorAll("button");
var total = 0;
for (let i = 0; i < btn.length; i++) {
btn[i].addEventListener("click", function() {
if (blocks[i].classList.contains("active")) {
blocks[i].classList.remove("active");
total--;
} else if (total < 3 && !blocks[i].classList.contains("active")) {
blocks[i].classList.add("active");
total++;
}
});
}
.container{
display:flex;
}
.block{
padding: 50px;
border:1px solid;
max-width:
}
.block.active{
background:grey;
}
<div class="container">
<div class="block">
<button>click</button>
</div>
<div class="block">
<button>click</button>
</div>
<div class="block">
<button>click</button>
</div>
<div class="block">
<button>click</button>
</div>
</div>

Add class if child element not present

If this works when a class is present...
$('.priority').children('.no-priority').addClass('normal');
How would I add a class if the child class .no-priority is missing?
Tried code below which does not work
if (!$('.priority').children('.no-priority')) {
$('.priority').addClass('prioritised');
}
Neither does
$('.priority').not('.no-priority').addClass('prioritised');
You can use :not(), :has()
$(".priority:not(:has(.no-priority))").addClass("normal")
.normal {
color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="priority">
<div class="does-not-have-no-priority">
does not have .no-priority
</div>
</div>
<div class="priority">
<div class="no-priority">
has .no-priority
</div>
</div>
Use filter
$('.priority').filter(function() {
return $(this).find('.no-priority').length === 0;
}).addClass('normal');
If I understand your question, you can do this in vanilla javascript:
var priority = document.querySelectorAll('.priority');
for (var i = 0; i < priority.length; i++) {
if (priority[i].querySelector('.no-priority')) {
priority[i].classList.add('normal');
} else {
priority[i].classList.add('prioritised');
}
}
.priority.normal {
color: red;
}
.priority.prioritised {
color: blue;
}
<div class="priority">
<div class="no-priority">no priority</div>
</div>
<div class="priority">
<div class="foo">priority</div>
</div>

Showing/Hiding Divs with Javascript on click

I'm trying to show/hide tabs on click using just Javascript but I'm getting errors ("Uncaught TypeError: Cannot set property 'className' of undefined tabs.(anonymous function).onclick"). Can someone give me an idea of what the issue might be?
<style>
a { text-decoration: none; }
li { list-style: none; }
li.selected { font-weight: bold; }
.panels div { display: none; }
.panels .selected { display: block; }
</style>
<div id="tabs" class="tabs">
<ul>
<li class="selected">One</li>
<li class="">Two</li>
<li class="">Three</li>
</ul>
</div>
<div id="panels" class="panels">
<div class="selected">This is panel one.</div>
<div class="">This is panel two.</div>
<div class="">This is panel three.</div>
</div>
<script>
var tabs = document.getElementById("tabs").getElementsByTagName("li");
var panels = document.getElementById("panels").getElementsByTagName("div");
for (var i = 0; i < tabs.length; i++) {
new function(i) {
tabs[i].onclick = function() {
tabs[i].className = panels[i].className = "selected";
for (var i = 0; i < panels.length; i++) {
tabs[i].className = panels[i].className = "";
}
}
}(i);
}
</script>
Your inner for loop has an i variable that conflict with the outter variable for loop with the same name.
You should also remove selected class from all elements before setting the clicked element 'selected'.
Try:
<script>
var tabs = document.getElementById("tabs").getElementsByTagName("li");
var panels = document.getElementById("panels").getElementsByTagName("div");
for (var i = 0; i < tabs.length; i++) {
new function(i) {
tabs[i].onclick = function() {
for (var j = 0; j < panels.length; j++) {
tabs[j].className = panels[j].className = "";
}
tabs[i].className = panels[i].className = "selected";
}
}(i);
}
</script>
You've got a couple of problems:
Multiple i variables
new function(i) {...} isn't the best syntax. I've used a closure below
multiple assignments per line isn't good
I've given your <li> elements values so that we can tell which li element has been clicked
var tabs = document.getElementById("tabs").getElementsByTagName("li");
var panels = document.getElementById("panels").getElementsByTagName("div");
for (var i = 0; i < panels.length; i++) {
(function(i) {
tabs[i].onclick = function() {
var j;
var panelIndex;
// remove styles from other tabs
for (j = 0; j < tabs.length; j++) {
tabs[j].className = "";
}
// apply style to the current tab: 'this'
this.className = "selected";
// hide other panels
for (j = 0; j < panels.length; j++) {
panels[j].className = "";
}
// show the selected panel
panelIndex = +this.value; // convert value to number
panels[panelIndex-1].className="selected"; // arrays are 0-indexed, so subtract 1
}
})(i);
}
a { text-decoration: none; }
li { list-style: none; }
li.selected { font-weight: bold; }
.panels div { display: none; }
.panels .selected { display: block; }
<div id="tabs" class="tabs">
<ul>
<li value="1" class="selected">One</li>
<li value="2" class="">Two</li>
<li value="3" class="">Three</li>
</ul>
</div>
<div id="panels" class="panels">
<div class="selected">This is panel one.</div>
<div class="">This is panel two.</div>
<div class="">This is panel three.</div>
</div>
Below here will work, as you are expecting. Two issues I found for accessing HTML Element inside for loop, you need to use .item() as its HTMLCollection you are getting instead of an array. Also your inner for loop needs to use different looping index, with one additional if condition to leave clicked one as shown and rest hidden.
<style>
a { text-decoration: none; }
li { list-style: none; }
li.selected { font-weight: bold; }
.panels div { display: none; }
.panels .selected { display: block; }
</style>
<div id="tabs" class="tabs">
<ul>
<li class="selected">One</li>
<li class="">Two</li>
<li class="">Three</li>
</ul>
</div>
<div id="panels" class="panels">
<div class="selected">This is panel one.</div>
<div class="">This is panel two.</div>
<div class="">This is panel three.</div>
</div>
<script>
var tabs = document.getElementById("tabs").getElementsByTagName("li");
var panels = document.getElementById("panels").getElementsByTagName("div");
for (var i = 0; i < tabs.length; i++) {
new function(i) {
tabs[i].onclick = function() {
tabs.item(i).className = panels.item(i).className = "selected";
for (var j = 0; j < panels.length; j++) {
if(i!=j){
tabs.item(j).className = panels.item(j).className = "";
}
}
}
}(i);
}
</script>

Categories

Resources