Mr. Rod
Mr. Rod

Reputation: 25

Vanilla Javascript: Remove toggle class from X element if I click on Y element with the same toggle class

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

Answers (3)

user4399002
user4399002

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.

  1. Create a function to handle the click action of the user and pass in the element that has been clicked as the parameter. function toggle(element){...}
  2. Inside that element first fire off an event to clear the selected element(s) using the event named clearselected that will iterate through the elements and set the selected property to false. Thus, semantically deselecting the elements.
  3. Change the selected property of the element passed in the onclick handler to true.
  4. Update the user interface (UI) using an event called 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

chipit24
chipit24

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

Barmar
Barmar

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

Related Questions