I'm a novice with JavaScript so bear with me.
I'm trying to use JavaScript to generate tabbed windows for specific bits of content. The HTML looks like this:
<div class="tab-win" id="tablinks-d38e44">
<button class="tablinks" data-target="tab-bash-d38e44">bash</button>
<button class="tablinks" data-target="tab-gui-d38e44">gui</button>
</div>
<div class="tabcontents" id="tabcontents-d38e44">
<div class="tabcontent" id="tab-bash-d38e44">This is bash.</div>
<div class="tabcontent" id="tab-gui-d38e44">This is plain old GUI...</div>
</div>
<p class="p">Here is another one.</p>
<div class="tab-win" id="tablinks-d38e56">
<button class="tablinks" data-target="tab-bash-d38e56">bash</button>
<button class="tablinks" data-target="tab-gui-d38e56">gui</button>
</div>
<div class="tabcontents" id="tabcontents-d38e56">
<div class="tabcontent" id="tab-bash-d38e56">This is bash #2.</div>
<div class="tabcontent" id="tab-gui-d38e56">This is plain old GUI..#2.</div>
</div>
</div>
I've cobbled together this function.
function tabbedWindows(evt, env) {
// Declare all variables
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(env).style.display = "block";
evt.currentTarget.className += " active";
}
If I add an onclick attribute directly to the button elements like so:
onclick="tabbedWindows(event,'content-id')"
it works great. However, I'm trying to mind separation of concerns and want to add the event dynamically. I'm trying to do this with the following:
const tab = document.querySelectorAll(".tablinks");
const content = document.querySelectorAll(".tabcontent");
for (let i = 0; i < tab.length; i++) {
let conId = tab[i].getAttribute('data-target');
let conArray = Array.from(content);
let con = conArray.find((c) => c.getAttribute('id') === conId);
let c = con.getAttribute('id');
tab[i].addEventListener('click', tabbedWindows(event,c), false);
}
This doesn't work due to the following error: main.js:23 Uncaught TypeError: Cannot read property 'currentTarget' of undefined. The line it's failing on is:
evt.currentTarget.className += " active";
I think the reason for this is by the time the function attempts to attach the listener, event variable is already out of scope. That is just what I've been able to glean from research. The long and the short of it is I'm stumped and not even sure if this is the correct approach. I guess some questions I have are:
- Why does 'event' work as a variable when passed through an onclick attribute but not when passed in as a parameter to the function invoked through the for loop? I think I've already answered this question but maybe someone more knowledgeable can provide a better description.
- My for loop seems unnecessarily convoluted. Am I overcomplicating things here? I'm guessing 'yes'.
Any help is appreciated.