Reputation: 103
I have 3 tabs, which I am using to switch table columns in mobile version. What I am trying to acheive, is to hide/show table columns clicking on suitable column button. My idea was to manipulate each column items class, which would be the same for all elements inside that column, but I got stuck, that I can't add .hidden class to a collection of items. Would be grateful for any advise on that. Or maybe there is a better way to manipulate tabs?
document.addEventListener('DOMContentLoaded', function() {
let tabsContainer = document.querySelector('.buynow-tabs');
let tabsButtons = tabsContainer.querySelectorAll('.buynow-tabs__tab');
let basicElements = document.querySelectorAll('.table-v4__tab-basic');
let premiumElements = document.querySelectorAll('.table-v4__tab-premium');
let eliteElements = document.querySelectorAll('.table-v4__tab-elite');
for (var i = 0; i < tabsButtons.length; i++) {
tabsButtons[i].addEventListener('click', function() {
let current = tabsContainer.querySelectorAll('.active');
current[0].className = current[0].className.replace(' active', '');
this.className += ' active';
if (tabsButtons[0].classList.contains('active')) {
basicElements.classList.remove('hidden');
premiumElements.classList.add('hidden');
eliteElements.classList.add('hidden');
} else if (tabsButtons[1].classList.contains('active')) {
basicElements.classList.add('hidden');
premiumElements.classList.remove('hidden');
eliteElements.classList.add('hidden');
} else if (tabsButtons[2].classList.contains('active')) {
basicElements.classList.add('hidden');
premiumElements.classList.add('hidden');
eliteElements.classList.remove('hidden');
}
});
}
});
.buynow-tabs {
display: flex;
}
<div class="buynow-tabs">
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab">Basic</button>
</div>
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab active">Premium</button>
</div>
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab">Elite</button>
</div>
</div>
<table>
<thead>
<tr>
<th class="table-v4__plans-basic">Basic</th>
<th class="table-v4__plans-premium">Premium</th>
<th class="table-v4__plans-elite">Elite</th>
</tr>
</thead>
<tbody>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
</tbody>
</table>
Upvotes: 1
Views: 811
Reputation: 5767
You have to iterate over the table cells with for loops and have to use the if-else-blocks inside that loops. Furthermore there was no CSS definition for the class .hidden
and the selectors in your js-code were wrong (table-v4__tab
instead of table-v4__plans
like in your html).
To let your hardcoded class active
for "Premium" come into account after page load you can trigger the click event for the premium button with:
document.querySelectorAll('.buynow-tabs__tab')[1].click();
Working example:
document.addEventListener('DOMContentLoaded', function() {
const tabsButtons = document.querySelectorAll('.buynow-tabs__tab');
const cells = document.querySelectorAll('[class^=table-v4__plans]');
const basicElements = document.querySelectorAll('.table-v4__plans-basic');
const premiumElements = document.querySelectorAll('.table-v4__plans-premium');
const eliteElements = document.querySelectorAll('.table-v4__plans-elite');
for (let i = 0; i < tabsButtons.length; i++) {
tabsButtons[i].addEventListener('click', function() {
const current = document.querySelector('.buynow-tabs__tab.active');
current.className = current.className.replace(' active', '');
this.className += ' active';
for (let i = 0; i < cells.length; i++) {
cells[i].classList.add('hidden');
}
for (let i = 0; i < basicElements.length; i++) {
if (tabsButtons[0].classList.contains('active')) {
basicElements[i].classList.remove('hidden');
}
}
for (let i = 0; i < premiumElements.length; i++) {
if (tabsButtons[1].classList.contains('active')) {
premiumElements[i].classList.remove('hidden');
}
}
for (let i = 0; i < eliteElements.length; i++) {
if (tabsButtons[2].classList.contains('active')) {
eliteElements[i].classList.remove('hidden');
}
}
});
}
document.querySelectorAll('.buynow-tabs__tab')[1].click();
});
.buynow-tabs {
display: flex;
}
.hidden {
display: none;
}
<div class="buynow-tabs">
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab">Basic</button>
</div>
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab active">Premium</button>
</div>
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab">Elite</button>
</div>
</div>
<table>
<thead>
<tr>
<th class="table-v4__plans-basic">Basic</th>
<th class="table-v4__plans-premium">Premium</th>
<th class="table-v4__plans-elite">Elite</th>
</tr>
</thead>
<tbody>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
</tbody>
</table>
But there is a much easier way if you add an id to each button (basic
, premium
and elite
). You just need to define one var for all table cells incl. th
(selected by the beginning of their class name [class^=table-v4__plans]
). In the click handler you then just have to compare the button id (e.target.id
) with the className
of the cell to decide whether you have to add or remove the class .hidden
(all that in one single for
loop).
Because i presumed that the class .active
is just for the script i omitted it in my second example. If it is important for styling etc. you can of course handle it in the click handler like you did or with this compressed version:
document.querySelector('button.active').className = e.target.className;
e.target.className = 'active';
Working example:
document.addEventListener('DOMContentLoaded', function() {
const cells = document.querySelectorAll('[class^=table-v4__plans]');
document.querySelector('.buynow-tabs').addEventListener('click', function(e) {
for (i = 0; i < cells.length; i++) {
if (cells[i].className.includes(e.target.id)) {
cells[i].classList.remove('hidden');
} else {
cells[i].classList.add('hidden');
}
}
});
document.querySelectorAll('.buynow-tabs__tab')[1].click();
});
.buynow-tabs {
display: flex;
}
.hidden {
display: none;
}
<div class="buynow-tabs">
<div class="buynow-tabs__item-container">
<button id="basic" class="buynow-tabs__tab">Basic</button>
</div>
<div class="buynow-tabs__item-container">
<button id="premium" class="buynow-tabs__tab">Premium</button>
</div>
<div class="buynow-tabs__item-container">
<button id="elite" class="buynow-tabs__tab">Elite</button>
</div>
</div>
<table>
<thead>
<tr>
<th class="table-v4__plans-basic">Basic</th>
<th class="table-v4__plans-premium">Premium</th>
<th class="table-v4__plans-elite">Elite</th>
</tr>
</thead>
<tbody>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
</tbody>
</table>
Upvotes: 1
Reputation: 4785
Like other people have pointed out, the reason why your code does not work is because you have to iterate over all the elements of your selector queries. But I think there is a more elegant way to solve your problem:
I would suggest you to alter just your style sheet when clicking the buttons instead of changing the classes of all your elements. It will greatly simplify your code and remove a lot of bugs altogether.
Here is an example of how you can do this:
First add a scriptable style sheet to the head of your document:
const selectedTabStyles = document.createElement('style')
document.head.appendChild(selectedTabStyles)
Then create a function to alter the stylesheet
function onlyShowSelectedPlan(plan) {
selectedTabStyles.innerHTML = `
th, td {display: none}
.table-v4__plans-${plan} {display: table-cell}
`
}
That's it for the scripting part! Now you can add your "plan selection" function as an onclick handler to your buttons
<button onclick="onlyShowSelectedPlan('basic')">Basic</button>
const selectedTabStyles = document.createElement('style')
document.head.appendChild(selectedTabStyles)
function onlyShowSelectedPlan(plan) {
selectedTabStyles.innerHTML = `th, td {display: none} .table-v4__plans-${plan} {display: table-cell}`
}
.buynow-tabs {
display: flex;
}
<div class="buynow-tabs">
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab" onclick="onlyShowSelectedPlan('basic')">Basic</button>
</div>
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab" onclick="onlyShowSelectedPlan('premium')">Premium</button>
</div>
<div class="buynow-tabs__item-container">
<button class="buynow-tabs__tab" onclick="onlyShowSelectedPlan('elite')">Elite</button>
</div>
</div>
<table>
<thead>
<tr>
<th class="table-v4__plans-basic">Basic</th>
<th class="table-v4__plans-premium">Premium</th>
<th class="table-v4__plans-elite">Elite</th>
</tr>
</thead>
<tbody>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
<tr>
<td class="table-v4__plans-basic">Basic</td>
<td class="table-v4__plans-premium">Premium</td>
<td class="table-v4__plans-elite">Elite</td>
</tr>
</tbody>
</table>
Upvotes: 1