Tabs how can I add next and prev buttons?
I'm have a tab component that needs the next and prev button as requirements.
I tried to build the component and now the extra bit is needed but I'm a bit stuck.
I'm not sure how to call the function and make it work within the existing one.
How do I add an extra click function for the buttons next and prev?
would be really useful to have it working. If anyone is able to put me on the right path, perhaps using a click even with some console.log in the right place?
class Tabs {
constructor() {
this.tabsBlocks = document.querySelectorAll(".tabs-block");
}
init() {
if (this.tabsBlocks.length > 0) {
Array.prototype.forEach.call(this.tabsBlocks, (tabBlock, index) => {
const tabContainer = tabBlock.querySelector(".tab-wrapper");
const tabs = tabBlock.querySelectorAll("button");
const panels = tabBlock.querySelectorAll(".panel");
const buttonNext = tabBlock.querySelector(".buttonNext");
const buttonPrev = tabBlock.querySelector(".buttonPrev");
tabContainer.setAttribute("role", "tablist");
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.open === "true") this.toggleTabs(tab, panels);
tab.setAttribute("role", "tab");
tab.setAttribute(
"aria-controls",
`panel-${tab.dataset.target}-block-${index 1}`
);
const associatedPanel = tabBlock.querySelector(
`[data-panel="${tab.dataset.target}"]`
);
if (associatedPanel !== null) {
associatedPanel.id = `panel-${tab.dataset.target}-block-${
index 1
}`;
tab.id = `tab-${tab.dataset.target}-block-${index 1}`;
}
tab.addEventListener("click", () => {
this.toggleTabs(tab, panels);
});
});
Array.prototype.forEach.call(panels, (panel) => {
const associatedTab = tabBlock.querySelector(
`[data-target="${panel.dataset.panel}"]`
);
panel.setAttribute("role", "tabpanel");
panel.setAttribute("aria-labelledby", `${associatedTab.id}`);
});
});
}
}
toggleTabs = (currentTab, panels, buttonNext, buttonPrev) => {
const tabs = currentTab.closest(".tabs-block").querySelectorAll("button");
const target = currentTab.dataset.target;
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.target !== target) {
tab.classList.remove("is-active");
tab.setAttribute("aria-selected", "false");
}
});
Array.prototype.forEach.call(panels, (panel) => {
if (panel.dataset.panel !== target) {
panel.classList.remove("is-active");
} else {
panel.classList.add("is-active");
currentTab.classList.add("is-active");
currentTab.setAttribute("aria-selected", "true");
}
});
};
}
const components = {
Tabs: new Tabs()
};
components.Tabs.init();
.tabs-block .tab-wrapper li {
flex: 1 1 0%;
text-align: center;
}
.tabs-block .tab-wrapper li button {
font-weight: lighter;
font-size: 20px;
}
.tabs-block .tab-wrapper li button.is-active {
font-weight: normal;
}
.tabs-block .panel {
display: none;
}
.tabs-block .panel.is-active {
display: block;
}
<section >
<ul >
<li><button data-target="1" data-open="true">Tab title 1</button></li>
<li><button data-target="2">Tab title 2</button></li>
</ul>
<div >
<div data-panel="1" >
<p>Panel 1 content</p>
</div>
<div data-panel="2" >
<p>Panel 2 content</p>
</div>
</div>
<button ><< Prev</button>
<button >Next >></button>
</section>
CodePudding user response:
You have to add eventListener to your button elements
buttonNext.addEventListener("click", myFunction);
buttonPrev.addEventListener("click", myFunction);
function myFunction() {
console.log("next")
}
CodePudding user response:
Here are your Button Elements
<button id="nextBtn" ><< Prev</button>
<button id="prevBtn" >Next >></button>
You have to get elements directly from DOM. use a unique class name or id for this purpose
const buttonNext = document.querySelector("#nextBtn");
const buttonPrev = document.querySelector("#prevBtn");
Now if the buttonNext and buttonPrev variables have the elements you can add eventListener. The event listener is of type click so whenever user clicks on any button the respective function will be called
buttonNext && buttonNext.addEventListener("click", handleNext);
buttonPrev && buttonPrev.addEventListener("click", handlePrev);
const handleNext = () => {
console.log("next")
}
const handlePrev = () => {
console.log("next")
}
I hope this will work for you. You can add any logic on next and prev buttons in respective functions
CodePudding user response:
Working codepen demo
class Tabs {
constructor() {
this.tabsBlocks = document.querySelectorAll(".tabs-block");
}
init() {
if (this.tabsBlocks.length > 0) {
Array.prototype.forEach.call(this.tabsBlocks, (tabBlock, index) => {
const tabContainer = tabBlock.querySelector(".tab-wrapper");
const tabs = tabBlock.querySelectorAll("button");
const panels = tabBlock.querySelectorAll(".panel");
const Navigate= () => {
const buttonNext = document.querySelector("#nextBtn");
const buttonPrev = document.querySelector("#prevBtn");
const handleNext = () => {
console.log("next");
};
const handlePrev = () => {
console.log("prev");
};
buttonNext && buttonNext.addEventListener("click", handleNext);
buttonPrev && buttonPrev.addEventListener("click", handlePrev);
}
Navigate()
tabContainer.setAttribute("role", "tablist");
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.open === "true") this.toggleTabs(tab, panels);
tab.setAttribute("role", "tab");
tab.setAttribute(
"aria-controls",
`panel-${tab.dataset.target}-block-${index 1}`
);
const associatedPanel = tabBlock.querySelector(
`[data-panel="${tab.dataset.target}"]`
);
if (associatedPanel !== null) {
associatedPanel.id = `panel-${tab.dataset.target}-block-${
index 1
}`;
tab.id = `tab-${tab.dataset.target}-block-${index 1}`;
}
tab.addEventListener("click", () => {
this.toggleTabs(tab, panels);
});
});
Array.prototype.forEach.call(panels, (panel) => {
const associatedTab = tabBlock.querySelector(
`[data-target="${panel.dataset.panel}"]`
);
panel.setAttribute("role", "tabpanel");
panel.setAttribute("aria-labelledby", `${associatedTab.id}`);
});
});
}
}
toggleTabs = (currentTab, panels, buttonNext, buttonPrev) => {
const tabs = currentTab.closest(".tabs-block").querySelectorAll("button");
const target = currentTab.dataset.target;
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.target !== target) {
tab.classList.remove("is-active");
tab.setAttribute("aria-selected", "false");
}
});
Array.prototype.forEach.call(panels, (panel) => {
if (panel.dataset.panel !== target) {
panel.classList.remove("is-active");
} else {
panel.classList.add("is-active");
currentTab.classList.add("is-active");
currentTab.setAttribute("aria-selected", "true");
}
});
};
}
const components = {
Tabs: new Tabs()
};
components.Tabs.init();
CodePudding user response:
This example works on codepen but does not in here.. Maybe babel
preprozessor does something which i do not know...
Copy this to codepen and you will be happy.
class ArrayUtils {
// getting next index in array
nextIndex(currentIndex, array) {
// if 0 OR 1 elements, index stays the same..
if(array.length < 2) return currentIndex
// if possible increment.
if(currentIndex < array.length -1) {
return currentIndex 1
}
// if index would exceed array size go to start.
return 0
}
// getting previous INdex in array:
previousIndex(currentIndex, array) {
// if 0 OR 1 elements, index stays the same..
if(array.length < 2) return currentIndex
// if possible decrement!
if(currentIndex > 0) {
return currentIndex - 1
}
// start at the end of array when end is reached ofc.
return array.length -1
}
}
class Tabs {
constructor() {
this.tabsBlocks = document.querySelectorAll(".tabs-block");
this.arrayUtils = new ArrayUtils()
}
paginate(btn, action) {
const block = btn.closest('.tabs-block')
const panels = block.querySelectorAll('.panel')
const tabs = block.querySelectorAll('.tab-wrapper > li > button')
const activeIndex = Array.from(tabs)
.findIndex(t => t.getAttribute('data-open'))
if (tabs.length < 2) {
console.log('0 OR 1 tabs to toggle so no action.')
return
}
var newActiveIndex
if(action === 'next') {
newActiveIndex = this.arrayUtils.nextIndex(activeIndex, tabs)
}
else if(action === 'previous') {
newActiveIndex = this.arrayUtils.previousIndex(activeIndex, tabs)
}
else {
throw 'Invalid toggle action ' action
}
tabs[activeIndex].removeAttribute('data-open')
tabs[newActiveIndex].setAttribute('data-open', 'true')
this.toggleTabs(tabs[newActiveIndex], panels)
}
init() {
if (this.tabsBlocks.length > 0) {
Array.prototype.forEach.call(this.tabsBlocks, (tabBlock, index) => {
const tabContainer = tabBlock.querySelector(".tab-wrapper");
const tabs = tabBlock.querySelectorAll(".tab-wrapper li button");
const panels = tabBlock.querySelectorAll(".panel");
tabContainer.setAttribute("role", "tablist");
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.open === "true") this.toggleTabs(tab, panels);
tab.setAttribute("role", "tab");
tab.setAttribute(
"aria-controls",
`panel-${tab.dataset.target}-block-${index 1}`
);
const associatedPanel = tabBlock.querySelector(
`[data-panel="${tab.dataset.target}"]`
);
if (associatedPanel !== null) {
associatedPanel.id = `panel-${tab.dataset.target}-block-${
index 1
}`;
tab.id = `tab-${tab.dataset.target}-block-${index 1}`;
}
tab.addEventListener("click", () => {
this.toggleTabs(tab, panels);
});
});
Array.prototype.forEach.call(panels, (panel) => {
const associatedTab = tabBlock.querySelector(
`[data-target="${panel.dataset.panel}"]`
);
panel.setAttribute("role", "tabpanel");
panel.setAttribute("aria-labelledby", `${associatedTab.id}`);
});
});
}
}
toggleTabs = (currentTab, panels) => {
const tabs = currentTab.closest(".tabs-block").querySelectorAll("button");
const target = currentTab.dataset.target;
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.target !== target) {
tab.classList.remove("is-active");
tab.setAttribute("aria-selected", "false");
}
});
Array.prototype.forEach.call(panels, (panel) => {
if (panel.dataset.panel !== target) {
panel.classList.remove("is-active");
} else {
panel.classList.add("is-active");
currentTab.classList.add("is-active");
currentTab.setAttribute("aria-selected", "true");
}
});
};
}
const components = {
Tabs: new Tabs()
};
components.Tabs.init();
.tabs-block .tab-wrapper li {
flex: 1 1 0%;
text-align: center;
}
.tabs-block .tab-wrapper li button {
font-weight: lighter;
font-size: rem(20px);
}
.tabs-block .tab-wrapper li button.is-active {
font-weight: normal;
}
.tabs-block .panel {
display: none;
}
.tabs-block .panel.is-active {
display: block;
}
<section >
<ul >
<li><button data-target="1" data-open="true">Tab title 1</button></li>
<li><button data-target="2">Tab title 2</button></li>
<li><button data-target="3">Tab title 3</button></li>
<li><button data-target="4">Tab title 4</button></li>
</ul>
<div >
<div data-panel="1" >
<p>Panel 1 content</p>
</div>
<div data-panel="2" >
<p>Panel 2 content</p>
</div>
<div data-panel="3" >
<p>Panel 3 content</p>
</div>
<div data-panel="4" >
<p>Panel 4 content</p>
</div>
</div>
<button onClick="components.Tabs.paginate(this, 'previous')"><< Prev</button>
<button onClick="components.Tabs.paginate(this, 'next')">Next >></button>
</section>