Reputation: 25
I'm currently working on a sidebar menu where I toggle the "selected" class on a category, which has the classname "sidebar-category".
With jQuery I can easily achieve my desired goal: after toggling the "selected" class (if I click on another category) the previous category gets the class removed and is then applied to the currently clicked category:
$('.sidebar-category').click(function() {
$(".sidebar-category").not(this).removeClass("selected");
$(this).toggleClass('selected');
});
My problem is that for this project I cannot use jQuery and must use vanilla Javascript.
So far I can achieve the toggling easily, but I'm not sure how I can remove the class when clicking on another category using vanilla Javascript. This is my current code:
var selectCategory = document.getElementsByClassName('sidebar-category');
for (var i = 0, l = selectCategory.length; i < l; i++) {
selectCategory[i].onclick = function() {
this.classList.toggle('selected');
}
}
Upvotes: 1
Views: 1894
Reputation:
This can be achieved with the Events API in JavaScript.
Using the onClick=""
property of an HTML element we can construct a toggling system.
function toggle(element){...}
clearselected
that will iterate through the elements and set the selected
property to false. Thus, semantically deselecting the elements.selected
property of the element passed in the onclick handler to true. updateui
that changed the selected element to its desired appearance, and all non-selected elements to their desired appearance using a for loop that iterates through all elements and looks at the selected
property.Down below I have a code snippet that uses vanilla JavaScript to create a toggle system on the UI. It has a very basic HTML that uses the same class names and adds very little CSS to make the demo easier to understand. I hope this is the thing you were looking for!
// Set up the HTML elements in JavaScript
var sidebar = document.getElementsByClassName("sidebar")[0];
var sidebarCategories = document.getElementsByClassName("sidebar-category");
// Add an event listener for clearing the selected elements
sidebar.addEventListener("clearselected", function(e) {
for(var i = 0; i < sidebarCategories.length; i++){
sidebarCategories[i].selected = false;
}
}, false);
// Add an event listener updating the UI to reflect changes
sidebar.addEventListener("updateui", function(e) {
for(var i = 0; i < sidebarCategories.length; i++){
var current = sidebarCategories[i];
if(current.selected){
current.textContent = "selected";
}else{
current.textContent = "";
}
}
}, false);
// Write a on click handler to handle the toggle
function toggle(element){
var event = document.createEvent("Event");
event.initEvent("clearselected", true, true);
element.dispatchEvent(event);
element.selected = true;
var event = document.createEvent("Event");
event.initEvent("updateui", true, true);
element.dispatchEvent(event);
}
.sidebar-category {
width: 100px;
height: 100px;
border: 3px solid black;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
}
<div class="sidebar">
<p>Click the boxes to see the toggle in action</p>
<div class="sidebar-category" onclick="toggle(this)"></div>
<div class="sidebar-category" onclick="toggle(this)"></div>
<div class="sidebar-category" onclick="toggle(this)"></div>
</div>
Upvotes: 0
Reputation: 6987
Assuming your target environment supports ES2015 (or you transpile your code to support such an environment), a declarative approach using Array.from
, filter
and forEach
can be achieved with the following code:
function toggleSelectedClass(event) {
Array.from(document.getElementsByClassName('sidebar-category'))
.filter(element => element !== event.target)
.forEach(element => {
element.classList.remove('selected')
element.setAttribute('aria-pressed', false);
});
event.target.classList.toggle('selected');
const pressed = event.target.getAttribute('aria-pressed') === 'true';
event.target.setAttribute('aria-pressed', String(!pressed));
}
.sidebar-category {
padding: 5px;
}
.selected {
background: blue;
color: white;
}
<div onclick="toggleSelectedClass(event)">
<button type="button" class="sidebar-category selected" aria-pressed="true">Click</button>
<button type="button" class="sidebar-category" aria-pressed="false">Click</button>
<button type="button" class="sidebar-category" aria-pressed="false">Click</button>
<button type="button" class="sidebar-category" aria-pressed="false">Click</button>
</div>
Note: getElementsByClassName
returns an HTMLCollection
, not an array, so Array.from
is required to use the array methods filter
and forEach
.
Note 2: Keep accessibility in mind when designing such a menu. A good reference for this is https://inclusive-components.design/toggle-button/.
Upvotes: 1
Reputation: 780909
The jQuery code that removes the selected
class is equivalent to a loop. So just write that loop in your event listener.
var selectCategory = document.getElementsByClassName('sidebar-category');
for (var i = 0, l = selectCategory.length; i < l; i++) {
selectCategory[i].onclick = function() {
for (var j = 0; j < l; j++) {
if (selectCategory[j] != this) {
selectCategory[j].classList.remove("selected");
}
}
this.classList.toggle('selected');
}
}
Upvotes: 3