In part 8 of converting jQuery to vanilla JavaScript, we convert the last parts of the showPanel function, and the code to add a click listener to the tabs, from jQuery to vanilla JavaScript.
JSLint says that the next part of the code to work on is the following:
Undeclared ‘$’. (tab href)
var panel = $(tab).attr("href");
That code isn’t getting the panel itself. We can confirm this by logging the panel variable to the console.
var panel = $(tab).attr("href");
console.log(panel);
#panel1
#panel2
#panel3
#panel1
So what’s more correct is that it’s a panelId instead.
const panelId = $(tab).attr("href");
const panel = $(panelId);
How do we get that href string in vanilla JavaScript? We can’t just use tab.href.
const panelId = tab.href;
console.log(panelId);
const panel = $(panelId);
Instead of id references, we get a fully qualified url instead.
http://127.0.0.1:8080/#panel1
http://127.0.0.1:8080/#panel2
http://127.0.0.1:8080/#panel3
http://127.0.0.1:8080/#panel1
There are a few ways to deal with that. One is to directly access the HTML href attribute of the element, and another is to use the hash method that’s a part of the location interface. I’ll use that second method this time.
const panelId = tab.hash;
const panel = $(panelId);
And we can now easily combine those two lines:
// const panelId = tab.hash;
// const panel = $(panelId);
const panel = $(tab.hash);
And use document.querySelector to get the element:
// const panel = $(tab.hash);
const panel = document.querySelector(tab.hash);
Undeclared ‘$’. (remove hide)
The next thing to convert is removing the hide class.
const panel = document.querySelector(tab.hash);
$(panel)[0].classList.remove("hide");
...
We can just replace $(panel)[0]
with panel
and this is all good to go.
const panel = document.querySelector(tab.hash);
// $(panel)[0].classList.remove("hide");
panel.classList.remove("hide");
...
Undeclared ‘$’. (add fade-in)
The last thing in this showPanel function to convert is adding a fade-in class.
const panel = document.querySelector(tab.hash);
panel.classList.remove("hide");
$(panel)[0].classList.add("fade-in");
}
We can do a similar replacement as with the remove hide code here too.
const panel = document.querySelector(tab.hash);
panel.classList.remove("hide");
// $(panel)[0].classList.add("fade-in");
panel.classList.add("fade-in");
}
Undeclared ‘$’. (tab click)
$(".tabs a").click(tabClickHandler);
Here we loop through each of the tab links, and attach the tabClickHandler.
A reliable way to convert this is a piece at a time. First by getting all of the tab links, then by looping through them, then finally converting what’s inside of the loop.
Here are the tab links:
// $(".tabs a").click(tabClickHandler);
const tabLinks = document.querySelector(".tabs a");
$(tabLinks).click(tabClickHandler);
And the tests break. Gah! I used querySelector instead of querySelectorAll again. Still, doing things this way helps us to easily find and fix the problem.
// const tabLinks = document.querySelector(".tabs a");
const tabLinks = document.querySelectorAll(".tabs a");
$(tabLinks).click(tabClickHandler);
Now we loop through the tabLinks:
const tabLinks = document.querySelectorAll(".tabs a");
// $(tabLinks).click(tabClickHandler);
tabLinks.forEach(function addClickHandler(tabLink) {
$(tabLink).click(tabClickHandler);
});
And lastly we use addEventListener to attach the handler to each tab.
const tabLinks = document.querySelectorAll(".tabs a");
tabLinks.forEach(function addClickHandler(tabLink) {
// $(tabLink).click(tabClickHandler);
tab.addEventListener("click", tabClickHandler);
});
But, that causes the tests to break, because jQuery is trying to use its own way to trigger a click on the first tab, and doesn’t know about addEventListener events.
$(".tabs li:first a").click();
So, we temporarily step back to the previous code:
const tabLinks = document.querySelectorAll(".tabs a");
tabLinks.forEach(function addClickHandler(tabLink) {
// tab.addEventListener("click", tabClickHandler);
$(tabLink).click(tabClickHandler);
});
and fix the first tab click problem instead.
First tab click
Here’s the code that clicks on the first tab.
$(".tabs li:first a").click();
It’s much easier now to get the first tab, for it’s just the first index in the tabLinks collection.
// $(".tabs li:first a").click();
tabLinks[0].click();
And we can now go back to finishing off the tab click listener.
Tab click listener
The last of the jQuery is being used to attach a tab click handler.
tabLinks.forEach(function addClickHandler(tabLink) {
$(tabLink).click(tabClickHandler);
});
Let’s use the vanilla JavaScript addEventListener to attach the handler.
const tabLinks = document.querySelectorAll(".tabs a");
tabLinks.forEach(function addClickHandler(tabLink) {
// $(tabLink).click(tabClickHandler);
tab.addEventListener("click", tabClickHandler);
});
And that’s the last of the jQuery code all converted to vanilla JavaScript.
Remove the jQuery library
We can now remove the jQuery library from the HTML code.
<!-- <script src="js/jquery.min.js"></script> -->
<script src="js/script.js"></script>
And it should be no surprise by now, the tests for the code continue to work perfectly well, and the tabs happily change panels with no trouble.
We have successfully removed all of the jQuery from this code, all while keeping the page fully working all throughout the process.
Next steps?
Is there anything else to be done? JSLint is happy with the code so there’s nothing urgent to be fixed, but it does show that there’s a lot of functions.
I can see that the functions are mainly related to either tabs or panels, so the next and possibly last part will attempt to bring together some of these related functions.