get index of child with event.currentTarget - javascript

How to get rid of jQuery's ".index()" here? All I am looking for is a native way to get the index of the button clicked, see source code below (works perfectly but I really couldn't find any Vanilla-JS solution for this and I don't want to use jQuery for such a small task). Thanks.
function navButtonClick(ev) {
var buttonIndex = $(ev.currentTarget).index(); /* How to get rid of jQuery? */
document.getElementById("output").innerHTML = buttonIndex;
}
function startTemplate() {
var i;
var navItems = document.querySelectorAll("#navigation button");
for (i=0; i < navItems.length; i++) {
navItems[i].addEventListener("click", navButtonClick);
}
}
document.addEventListener("DOMContentLoaded", startTemplate);
The HTML part looks like this:
<nav id="navigation" role="navigation">
<button type="button"> <em>Navi tab 1</em> </button>
<button type="button"> Navi tab 2 </button>
<button type="button"> Navi tab 3 </button>
<button type="button"> Navi tab 4 </button>
</nav>
<div id="output"></div>

You can do it like this:
function navButtonClick(ev) {
var buttonIndex = Array.prototype.indexOf.call(this.parentElement.children, this);
document.getElementById("output").innerHTML = buttonIndex;
}
function startTemplate() {
var i;
var navItems = document.querySelectorAll("#navigation button");
for (i=0; i < navItems.length; i++) {
navItems[i].addEventListener("click", navButtonClick);
}
}
document.addEventListener("DOMContentLoaded", startTemplate);
Check the snippet below:
function navButtonClick(ev) {
var buttonIndex = Array.prototype.indexOf.call(this.parentElement.children, this);
document.getElementById("output").innerHTML = buttonIndex;
}
function startTemplate() {
var i;
var navItems = document.querySelectorAll("#navigation button");
for (i = 0; i < navItems.length; i++) {
navItems[i].addEventListener("click", navButtonClick);
}
}
document.addEventListener("DOMContentLoaded", startTemplate);
<nav id="navigation" role="navigation">
<button type="button"> <em>Navi tab 1</em>
</button>
<button type="button">Navi tab 2</button>
<button type="button">Navi tab 3</button>
<button type="button">Navi tab 4</button>
</nav>
<div id="output"></div>

You can do this in two different ways. First, pass the index of the buttons to the corresponding function while adding the event listeners:
function navButtonClick(buttonIndex) {
document.getElementById("output").innerHTML = buttonIndex;
}
function startTemplate() {
var i;
var navItems = document.querySelectorAll("#navigation button");
for (i = 0; i < navItems.length; i++) {
navItems[i].addEventListener("click", navButtonClick.bind(null, i));
}
}
startTemplate();
JSFiddle
Second, create a function which will dynamically check the index of the element:
function navButtonClick() {
document.getElementById("output").innerHTML = getIndex(this);
}
function getIndex(elm) {
var parent = elm.parentElement;
for (var i = 0; i < parent.children.length; i++) {
if (parent.children[i].isEqualNode(elm)) {
return i;
}
}
}
function startTemplate() {
var i;
var navItems = document.querySelectorAll("#navigation button");
for (i = 0; i < navItems.length; i++) {
navItems[i].addEventListener("click", navButtonClick);
}
}
startTemplate();
JSFiddle

<script>
function navButtonClick(index) {
return function (ev) {
document.getElementById("output").innerHTML = index;
}
}
function startTemplate() {
var i;
var navItems = document.querySelectorAll("#navigation button");
for (i=0; i < navItems.length; i++) {
navItems[i].addEventListener("click", navButtonClick(i));
}
}
document.addEventListener("DOMContentLoaded", startTemplate);
</script>

Hope, it works :)
Anyway, only for buttons (I need closest in chrome even for them).
document.addEventListener('click', function (event) {
var target = event.target, nodes, i;
if (target.closest) {
target = target.closest('button');
}
if (target && target.tagName === 'BUTTON') {
nodes = target.parentElement.children;
for (i=0; nodes[i]!==target; ++i);
document.querySelector("output").textContent = i;
}
})
<nav id="navigation" role="navigation">
<button type="button"> <em>Navi tab 1</em> </button>
<button type="button"> Navi tab 2 </button>
<button type="button"> Navi tab 3 </button>
<button type="button"> Navi tab 4 </button>
</nav>
<output></output>

ES6-style answer:
const indexOf = element => Array.from(element.parentNode.children).indexOf(element)
const buttonIndex = indexOf(event.currentTarget)

Related

Getting Random Nulls on .querySelector() in for Loop

<div id="agg-filter-buttons">
<button class="btn filter-btn" onclick="filterSelection(event)"><span data-
value="freespins">Free Spins <div class="num-brands"></div> </span></button>
<button class="btn filter-btn" onclick="filterSelection(event)"> <span data-value="bigbonus">Big Bonus <div class="num-brands"></div> </span></button> </div>
enter code here
</div>
<div class="brand-row the-table-row all row-1 filterDiv bigbonus newPlay show">
Row 1
</div>
<div class="brand-row the-table-row all row-2 filterDiv freespins newPlay show">
Row 2
</div>
filterSelection();
function filterSelection(e) {
var x, i, c;
x = document.getElementsByClassName("filterDiv");
var allBtns = document.getElementsByClassName("filter-btn")
for(i = 0; i<allBtns.length; i++){
let rowsAffected = allBtns[i].querySelector('.num-brands');
rowsAffected.innerText = '';
}
c = "all";
if(e && e.target.dataset){
c = e.target.dataset.value ? e.target.dataset.value : "all";
}
const numBrands = [];
for (i = 0; i < x.length; i++) {
x[i].classList.remove('show');
void x[i].offsetWidth;
if (x[i].classList.contains(c)) {
x[i].classList.add('show');
numBrands.push(i);
}
}
if(e && e.target){
e.srcElement.children[0].innerText = ` (${numBrands.length})`;
}
}
// Add active class to the current control button (highlight it)
var btnContainer = document.getElementById("agg-filter-buttons");
var btns = btnContainer.getElementsByClassName("filter-btn");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function($this) {
var current = document.querySelectorAll(".active-btn");
current[0].className = current[0].className.replace(" active-btn", "");
this.className += " active-btn";
});
}
var filter = document.getElementById('agg-filter-buttons');
filter.addEventListener('click', function(){
document.getElementsByClassName('section--btable')[0].classList.add('flash');
});
filterSelection();
function filterSelection(e) {
var x, i, c;
x = document.getElementsByClassName("filterDiv");
var allBtns = document.getElementsByClassName("filter-btn")
for (i = 0; i < allBtns.length; i++) {
let rowsAffected = allBtns[i].querySelector('.num-brands');
rowsAffected.innerText = '';
}
c = "all";
if (e && e.target.dataset) {
c = e.target.dataset.value ? e.target.dataset.value : "all";
}
const numBrands = [];
for (i = 0; i < x.length; i++) {
x[i].classList.remove('show');
void x[i].offsetWidth;
if (x[i].classList.contains(c)) {
x[i].classList.add('show');
numBrands.push(i);
}
}
if (e && e.target) {
e.srcElement.children[0].innerText = ` (${numBrands.length})`;
}
}
// Add active class to the current control button (highlight it)
var btnContainer = document.getElementById("agg-filter-buttons");
var btns = btnContainer.getElementsByClassName("filter-btn");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function($this) {
var current = document.querySelectorAll(".active-btn");
current[0].className = current[0].className.replace(" active-btn", "");
this.className += " active-btn";
});
}
var filter = document.getElementById('agg-filter-buttons');
filter.addEventListener('click', function() {
document.getElementsByClassName('section--btable')[0].classList.add('flash');
});
<div id="agg-filter-buttons">
<button class="btn filter-btn" onclick="filterSelection(event)"><span data-
value="freespins">Free Spins <div class="num-brands"></div> </span></button>
<button class="btn filter-btn" onclick="filterSelection(event)"> <span data-value="bigbonus">Big Bonus <div class="num-brands"></div> </span></button> </div>
enter code here
</div>
>
<div class="brand-row the-table-row all row-1 filterDiv bigbonus newPlay show">
Row 1
</div>
<div class="brand-row the-table-row all row-2 filterDiv freespins newPlay show">
Row 2
</div>
So I have a table with rows. These are filtered with the filter buttons. When you click a filter button it shows only the rows with the same name in its class. This works and populates the button with how many rows are affected.
However this breaks occasionally and I have no idea why.
the Variable rowsAffected works until it becomes null for some unknown reason.
My guess is that the dom eventually doesnt load fast enough for the querySelector to be able to read it. But im not sure.. Any advice very welcome!
I have also added a fiddle
https://jsfiddle.net/8z56sxby/
Since you only care about the first .active-btn (because there is at most one), you can just use querySelector.
Make sure there is a current before you do anything with its classes.
Use element.classList.add and element.classList.remove to add or remove classes.
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
var current = document.querySelector(".active-btn");
if (current) current.classList.remove("active-btn");
this.classList.add("active-btn");
});
}
Thankyou
The answer to this question was that clicks on my button were sometimes clicking child elements which were not setup to handle the click.
A silly mistake - that someone may find useful in the future.

Only the last button's onclick works

I inserted into .content some buttons with innerHTML, and I used addEventListener to got the onclick event and show a message when each button clicked. The problem is that only the last button's onclick works, What is the problem?
var x = document.getElementById("content");
for(let i = 0; i < 2; i++)
{
x.innerHTML += `
<button type="button" class="click-btn" id="click-btn-id" value="${i}">
click me
</button>
`;
// get last button that was INNER to .content
var btn_option = document.getElementsByClassName("click-btn");
var btn = btn_option[btn_option.length - 1];
btn.addEventListener("click", () => {
console.log('clicked!');
});
}
body {
background: black;
}
button {
margin-top: 30px;
}
<div id="content">
</div>
Using var btn = btn_option[btn_option.length - 1] makes you select the second button as btn-option.length - 1 is 1. Thats means you select the button at index 1. and not both 0 & 1.
Try using
var x = document.getElementById("content");
for(let i = 0; i < 2; i++)
{
x.innerHTML += `
<button type="button" class="click-btn" id="click-btn-id" value="${i}">
click me
</button>
`;
var btn_option = document.getElementsByClassName("click-btn");
btn-option.addEventListener("click", () => {
console.log('clicked!');
});
}
It's because you override the content by setting innerHTML directly. The working way is to append button html to the DOM using insertAdjacentHTML, for example.
var x = document.getElementById("content");
for (let i = 0; i < 2; i++) {
buttonHTML = `
<button type="button" class="click-btn" id="click-btn-id" value="${i}">
click me
</button>
`;
x.insertAdjacentHTML("beforeend", buttonHTML);
// get last button that was INNER to .content
var btn_option = document.getElementsByClassName("click-btn");
var btn = btn_option[btn_option.length - 1];
btn.addEventListener("click", () => {
console.log("clicked!");
});
}
body {
background: black;
}
button {
margin-top: 30px;
}
<div id="content">
</div>
try this code
var wrapper = document.getElementById("content")
wrapper.addEventListener("click", function(ev){
var btn_option = document.getElementsByClassName("click-btn");
Object.keys(btn_option).forEach(function(key){
if(ev.target == btn_option[key]){
console.log("btn "+ btn_option[key].getAttribute("value") +" click")
}
})
})
for(var i = 0; i < 2; i++){
wrapper.innerHTML += `
<button type="button" class="click-btn" value="${i}">
click me
</button>
`;
}
<div id="content">
</div>
body {
background: black;
}
button {
margin-top: 30px;
}
You also can loop your code like this.
var x = document.getElementById("content");
for(let i = 0; i < 2; i++) {
x.innerHTML += `<button type="button" class="click-btn" id="click-btn-id" value="${i}"> click me</button>`;
// get last button that was INNER to .content
var btn_option = document.getElementsByClassName("click-btn");
var len=btn_option.length;
for (let i=0; i<len; i++){
var btn = btn_option[i];
btn.addEventListener("click", () => {
console.log('clicked!'+i);
});
};
}

Access array inside Jquery using for loop

Hi guys I am trying to loop through 2 arrays , one array handles button Ids , the other handles the text. However it does not seem to be able to iterate through the text array. When I try to window.alert the value , it returns undefined.
var buttonIdArray = ['#one', '#two']
var textArray = ['this is button one', 'this is button two']
function buttonDetails() {
for (var i = 0; i < buttonIdArray.length; i++) {
$(buttonIdArray[i]).click(function() {
window.alert(textArray[i])
})
}
}
<button id ='one'>one</button>
<button id ='two'>two</button>
Because of the different scope in the .click() context you need to get your text from textArray before, like this:
var buttonIdArray = ['#one', '#two']
var textArray = ['this is button one', 'this is button two']
function buttonDetails() {
for (var i = 0; i < buttonIdArray.length; i++) {
const text = textArray[i]
$(buttonIdArray[i]).click(function() {
window.alert(text)
})
}
}
buttonDetails()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='one'>one</button>
<button id='two'>two</button>
You can use index() of jQuery.(like below)
var buttonIdArray = ['#one','#two'];
var textArray=['this is button one','this is button two'];
for (var i =0; i<buttonIdArray.length;i++)
{
$(buttonIdArray[i]).click(function(){
console.log(textArray[$(this).index()-1]);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id ='one'>1</button>
<button id ='two'>2</button>
This is how I would do it.
var textArray=["this is button 1","this is button 2"];
$('.myButtons').click(function(){
var index = $(this).index();
alert(textArray[index]);
});
<button class='myButtons' id="one">
Button 1
</button>
<button class='myButtons' id="two">
Button2
</button>
JS fiddle here
Or like this...
$('.myButtons').click(function(){
alert($(this).data('text'));
});
<button class='myButtons' id="one" data-text="this is my text">
Button 1
</button>
<button class='myButtons' id="two" data-text="this is my text 2">
Button2
</button>
Or like this...
var buttonArray =[
{id:'#one',text:"this is button1"},
{id:'#two',text:"this is button2"}
];
for (var i = 0; i < buttonArray.length; i++) {
var index = i;
$(buttonArray[index].id).click(function() {
alert(buttonArray[index].text);
});
}
Js Fiddle 2
Or Like this...
var buttonIdArray = ['#one', '#two']
var textArray = ['this is button one', 'this is button two']
function buttonDetails() {
for (var i = 0; i < buttonIdArray.length; i++) {
var text = textArray[i]
$(buttonIdArray[i]).click(function() {
window.alert(text)
})
}
}
buttonDetails()
There is probably a better way to do it than this, but this is how I solved your issue.
var buttonIdArray = ['#one', '#two']
var textArray = ['this is button one', 'this is button two']
function buttonDetails() {
for (var i = 0; i < buttonIdArray.length; i++) {
$(buttonIdArray[i]).attr('textArrayIndex', i)
}
}
$('button').click( function() {
window.alert(textArray[$(this).attr('textArrayIndex')]);
})
buttonDetails();
Basically, you can't have an event listener within a loop. It doesn't work.
JSFiddle

How do I run the same javascript with incrementing variable names

I have the following code, I know it's super inefficient, though I don't know how to make it simpler. Is there a way that button1 could just be changed to buttonX and everything could just be written once?
Apologies if this has been asked before. I have tried searching but it is quite a complicated thing to describe and I haven't found anything relevant.
var button1 = document.getElementById('toggle1');
var button2 = document.getElementById('toggle2');
var button3 = document.getElementById('toggle3');
var button4 = document.getElementById('toggle4');
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
var div3 = document.getElementById('div3');
var div4 = document.getElementById('div4');
button1.onclick = function() {
div1.style.display = 'block';
div2.style.display = 'none';
div3.style.display = 'none';
div4.style.display = 'none';
};
button2.onclick = function() {
div1.style.display = 'none';
div2.style.display = 'block';
div3.style.display = 'none';
div4.style.display = 'none';
};
button3.onclick = function() {
div1.style.display = 'none';
div2.style.display = 'none';
div3.style.display = 'block';
div4.style.display = 'none';
};
button4.onclick = function() {
div1.style.display = 'none';
div2.style.display = 'none';
div3.style.display = 'none';
div4.style.display = 'block';
};
Have a try with this - I have taken your code as example since you did not post HTML
The advantage of these two examples is that when you need to add a button and a div, the code does not change at all.
const buttons = document.querySelectorAll("[id^toggle]");
for (let i = 0; i < buttons.length; i++) {
buttons[i].onclick = function() {
const divs = document.querySelectorAll("[id^=div]");
for (let i = 0; i < divs.length; i++) {
divs[i].style.display = divs[i].id == "div" + this.id.replace("toggle", "") ? "block" : "none";
}
}
}
Instead of ID selector and replace, you can use classes and data-attr
const buttons = document.querySelectorAll(".toggleButton");
for (let i = 0; i < buttons.length; i++) {
buttons[i].onclick = function() {
const divs = document.querySelectorAll(".toggleDiv");
const showId = this.getAttribute("data-toggle");
for (let i = 0; i < divs.length; i++) {
divs[i].style.display = divs[i].id == showId ? "block" : "none";
}
}
}
assuming <button data-toggle="div1" class="toggleButton" type="button">Div1</button>
Consider placing everything into an array so you can do things by index.
var buttons = [];
var divs = [];
for(let i = 0; i < 4; i++) {
buttons[i] = document.getElementById('toggle'+(i+1));
divs[i] = document.getElementById('div'+(i+1));
buttons[i].addEventListener('click', doClick(i));
}
function doClick(index) {
return function() {
for(let i = 0; i < 4; i++) {
divs[i].style.display = i === index ? 'block' : 'none';
}
};
}
doClick(0)();
<div id="div1">One</div>
<div id="div2">Two</div>
<div id="div3">Three</div>
<div id="div4">Four</div>
<button id="toggle1">1</button>
<button id="toggle2">2</button>
<button id="toggle3">3</button>
<button id="toggle4">4</button>
In this code I am getting all four buttons and divs in a loop and setting up the event listeners for each button.
The function doClick is a curried function that uses a closure to set the index of the button that is being clicked on so we know which one we want to show and then we hide all of the others.
With jQuery you could do the following:
$('.toggleButton').on('click', function() {
var toggleDivId = '#toggleDiv' + $(this).attr('id').replace('toggleButton', '');
$('.toggleDiv').css('display', 'none');
$(toggleDivId).css('display', 'block');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="toggleButton1" class="toggleButton">Button 1</button>
<button id="toggleButton2" class="toggleButton">Button 2</button>
<button id="toggleButton3" class="toggleButton">Button 3</button>
<button id="toggleButton4" class="toggleButton">Button 4</button>
<div id="toggleDiv1" class="toggleDiv">Div 1</div>
<div id="toggleDiv2" class="toggleDiv">Div 2</div>
<div id="toggleDiv3" class="toggleDiv">Div 3</div>
<div id="toggleDiv4" class="toggleDiv">Div 4</div>
You can use javascript objects of course!
// let's match keys (1, 2, 3, 4) to buttons
var buttons = {
1: document.getElementById('toggle1'),
2: document.getElementById('toggle2'),
3: document.getElementById('toggle3'),
4: document.getElementById('toggle4')
}
// let's match keys (1, 2, 3, 4) to divs
var divs = {
1: document.getElementById('div1'),
2: document.getElementById('div2'),
3: document.getElementById('div3'),
4: document.getElementById('div4')
}
// this function will hide all divs except the once given as a param
function hideAllBut(index) {
// go through each div
for (var i = 1; i <= 4; i++) {
// if i is equal to the param, display the div
if (i === index) {
divs[i].style.display = 'block'; // accessing the divs object which has key i
} else {
// else hide it
divs[i].style.display = 'none';
}
}
}
// now for each button, we call the function to hide all expect the one we want
buttons[1].onclick = function () {
hideAllBut(1);
};
buttons[2].onclick = function () {
hideAllBut(2);
};
buttons[3].onclick = function () {
hideAllBut(3);
};
buttons[4].onclick = function () {
hideAllBut(4);
};
Keeping that in mind, we can make the code even more dynamic
var buttons = {};
var divs = {};
// how many elements we have (here 4)
var totalElements = 4;
// assign buttons and divs values dynamically, while adding the onclick
for (var i = 1; i <= totalElements; i++) {
buttons[i] = document.getElementById('toggle' + i); // i.e. if i=1, 'toggle'+i = 'toggle1'
divs[i] = document.getElementById('div' + i);
buttons[i].onclick = function () {
hideAllBut(i);
};
}
// this function does the same as how we wrote it perviously but with a different format
function hideAllBut(index) {
for (var i = 1; i <= totalElements; i++) {
// we use the ternary operator
divs[i].style.display = (i === index) ? 'block' : 'none';
}
}
Read the documentation of the javascript object because you're gonna use it a lot and will help you do stuff dynamically. https://www.w3schools.com/js/js_objects.asp
Ternary operator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
Here's an example using jQuery, that helps to avoid having to declare all the vars for each button first.
I also added a 'reset' button so you can get all the divs back. I'm not sure if this is what you wanted but to me this seems like the kind of thing jQuery is especially helpful for, so here is an example:
$('button').on('click', function(){
$('.boxdiv').css({"display":"none"});
switch ($(this).attr('id')) {
case "1":
case "2":
case "3":
case "4":
$(`#div${$(this).attr('id')}`).css({"display":"block"});
break;
case "reset":
$('.boxdiv').css({"display":"block"});
break;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="float:left">
<button class="button" id="1">B1</button>
<button class="button" id="2">B2</button>
<button class="button" id="3">B3</button>
<button class="button" id="4">B4</button>
<button class="button" id="reset">Reset</button>
</div>
<br/>
<br/>
<div class="boxdiv" id="div1" style="background-color:red;width:60px;height:60px;float:left;">
</div>
<div class="boxdiv" id="div2"style="background-color:yellow;width:60px;height:60px;float:left;">
</div>
<div class="boxdiv" id="div3"style="background-color:blue;width:60px;height:60px;float:left;">
</div>
<div class="boxdiv" id="div4"style="background-color:green;width:60px;height:60px;float:left;">
</div>

How do you show current tab in javascript for loop and hide all others tabs using ES6

I got the tabs to work but the issue is that I really don't think this follows javascript's don't repeat yourself. As you can see from my code I had to create individual loops for each tab so just that tab would show. The idea is you click the tab and just the description block for that particular tab would show. click tab[0] show just descriptionBlock[0] etc...i also want the initial descriptionBlock to show on pageload. Please no jquery, ES6 javascript is the ideal. Any suggestions would be helpful...
//Product Overview Tabs
const tabs = document.querySelectorAll('.tablist li');
const descriptionBlock = document.querySelectorAll('.descriptionBlock');
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener('click', (ev) => { ev.preventDefault(); });
}
tabs[0].onclick = () => {
descriptionBlock[0].style.display = "block";
for (let i = 1; i < descriptionBlock.length; i++) {
descriptionBlock[i].style.display = "none";
}
}
tabs[1].onclick = () => {
descriptionBlock[1].style.display = "block";
for (let i = 0; i < descriptionBlock.length; i++) {
if (i === 1) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[2].onclick = () => {
descriptionBlock[2].style.display = "block";
for (let i = 0; i < descriptionBlock.length; i++) {
if (i === 2) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[3].onclick = () => {
descriptionBlock[3].style.display = "block";
for (let i = 0; i < descriptionBlock.length; i++) {
if (i === 3) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[4].onclick = () => {
descriptionBlock[4].style.display = "block";
for (let i = 0; i < descriptionBlock.length; i++) {
if (i === 4) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[5].onclick = () => {
descriptionBlock[5].style.display = "block";
for (let i = 0; i < descriptionBlock.length; i++) {
if (i === 5) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[6].onclick = () => {
descriptionBlock[6].style.display = "block";
for (let i = 0; i < descriptionBlock.length; i++) {
if (i === 6) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[7].onclick = () => {
descriptionBlock[7].style.display = "block";
for (let i = 0; i < 8; i++) {
if (i === 7) {
continue;
}
descriptionBlock[i].style.display = "none";
}
}
tabs[8].onclick = () => {
descriptionBlock[8].style.display = "block";
for (let i = 0; i < 8; i++) {
descriptionBlock[i].style.display = "none";
}
}
<div class="overview-wrapper" id="overview">
<h2>Pro<span>duct Overv</span>iew</h2>
<div>
<div class="product-tabs">
<div class="miniproduct-wrapper">
<img src="/_img/models/Model_J.png" alt="Model J" title="Model J" width="150" height="150">
<h3>Model J6</h3>
</div>
<div>
<div class="down-arrow"></div>
</div>
<ul class="tablist">
<li>Key Features</li>
<li>Specifications</li>
<li>Dimensions</li>
<li>Product Builder</li>
<li>Sizing Chart</li>
<li>Dish Machine<br>Cross Reference<br>Chart</li>
<li>Options</li>
<li>Support</li>
<li>Faqs</li>
</ul>
</div>
<div class="description-tabs">
<div class="descriptionBlock" style="display:block;">1</div>
<div class="descriptionBlock">2</div>
<div class="descriptionBlock">3</div>
<div class="descriptionBlock">4</div>
<div class="descriptionBlock">5</div>
<div class="descriptionBlock">6</div>
<div class="descriptionBlock">7</div>
<div class="descriptionBlock">8</div>
<div class="descriptionBlock">9</div>
</div>
</div>
</div>
Define a function showBlock(index) that loops over blocks and shows the one with corresponding index. Loop over tabs and add event listener that calls showBlock with corresponding index. Also you might want to google for event delegation to avoid adding multiple event listeners.
const tabs = document.querySelectorAll('.tablist li')
const descriptionBlocks = document.querySelectorAll('.descriptionBlock')
const entries = function*(iterable) {
let i = 0;
for (item of iterable) {
yield [i++, item]
}
}
const showBlock = index => {
for (const [blockIndex, block] of entries(descriptionBlocks)) {
block.style.display = blockIndex === index ? 'block' : 'none'
}
}
showBlock(0)
for (const [tabIndex, tab] of entries(tabs)) {
tab.addEventListener('click', ev => {
ev.preventDefault()
showBlock(tabIndex)
})
}
<div class="overview-wrapper" id="overview">
<h2>Pro<span>duct Overv</span>iew</h2>
<div>
<div class="product-tabs">
<div class="miniproduct-wrapper">
<img src="/_img/models/Model_J.png" alt="Model J" title="Model J" width="150" height="150">
<h3>Model J6</h3>
</div>
<div>
<div class="down-arrow"></div>
</div>
<ul class="tablist">
<li>Key Features</li>
<li>Specifications</li>
<li>Dimensions</li>
<li>Product Builder</li>
<li>Sizing Chart</li>
<li>Dish Machine<br>Cross Reference<br>Chart</li>
<li>Options</li>
<li>Support</li>
<li>Faqs</li>
</ul>
</div>
<div class="description-tabs">
<div class="descriptionBlock" style="display:block;">1</div>
<div class="descriptionBlock">2</div>
<div class="descriptionBlock">3</div>
<div class="descriptionBlock">4</div>
<div class="descriptionBlock">5</div>
<div class="descriptionBlock">6</div>
<div class="descriptionBlock">7</div>
<div class="descriptionBlock">8</div>
<div class="descriptionBlock">9</div>
</div>
</div>
</div>
If I clearly understand, just save current selected index and update in click handler:
const tabs = document.querySelectorAll('.tablist li');
const descriptions = document.querySelectorAll('.descriptionBlock');
let selectedIndex = 0;
tabs.forEach((tab, i) => {
// if you really need to do initial "none" assignment in js
// instead add display none to your css
descriptions[i].style.display = "none";
tab.addEventListener('click', (ev) => {
ev.preventDefault();
descriptions[selectedIndex].style.display = "none";
descriptions[i].style.display = "block";
selectedIndex = i;
});
});
// select default tab
tabs[selectedIndex].click();
Profit!
P.S. You can save whole description block, but if you store index it will be helpful for working with both selected tab and description block.
You can just put the common code in a function which I will call showTab() and then use a loop to add all the click listeners and then just call the common function from each listener:
const tabs = Array.from(document.querySelectorAll('.tablist li'));
const descriptionBlock = document.querySelectorAll('.descriptionBlock');
function showTab(n) {
for (let i = 0; i < descriptionBlock.length; i++) {
descriptionBlock[i].style.display = "none";
}
descriptionBlock[n].style.display = "block";
}
for (let [i, tab] of tabs.entries()) {
tab.addEventListener('click', (ev) => {
ev.preventDefault();
showTab(i);
});
}

Categories