'How to check className in a switch statement when an element has multiple classes
In the example below I just want the option clicked to display in an alert. I'm trying to use a switch statement to determine what class was clicked. My example would work if my divs did not each contain more than one class. I tried using classList.contains in my switch statement to no avail. Is there a way I can get this working without changing my use of a switch statement?
function optionClicked(){
switch( this.className ){
case 'option1':
alert( 'user clicked option1' );
break;
case 'option2':
alert( 'user clicked option2' );
break;
case 'option3':
alert( 'user clicked option3' );
break;
}
}
function optionTabs(){
var optionTabs = document.querySelectorAll( 'div' ),
i = 0;
for( i; i < optionTabs.length; i++ ){
optionTabs[ i ].addEventListener( 'click', optionClicked );
}
}
optionTabs();
html {
background-color: #eee;
font-family: sans-serif;
}
div {
cursor: pointer;
margin: 1.1rem;
padding: 1rem;
background-color: #fff;
letter-spacing: 0.05rem;
border-radius: 1rem;
}
div:hover {
background-color: #555;
color: #eee;
}
<div class="option1 more">option 1</div>
<div class="option2 classes">option 2</div>
<div class="option3 here">option 3</div>
Solution 1:[1]
The following should work in your switch statement:
function optionClicked(){
var cls = this.classList;
switch( true ){
case cls.contains('option1'):
alert( 'option1' );
break;
case cls.contains('option2'):
alert( 'option2' );
break;
case cls.contains('option3'):
alert( 'option3' );
break;
}
}
function optionTabs(){
var optionTabs = document.querySelectorAll( 'div' ),
i = 0;
for( i; i < optionTabs.length; i++ ){
optionTabs[ i ].addEventListener( 'click', optionClicked );
}
}
optionTabs();
html {
background-color: #eee;
font-family: sans-serif;
}
div {
cursor: pointer;
margin: 1rem;
padding: 1rem;
background-color: #fff;
letter-spacing: 0.05rem;
}
div:hover {
background-color: #555;
color: #eee;
}
<div class="option1 more">option 1</div>
<div class="option2 classes">option 2</div>
<div class="option3 here">option 3</div>
Solution 2:[2]
Use a RegExp to extract relevant classes from the className:
function optionClicked(){
switch((this.className.match(/\boption\d+\b/) || [])[0]){
case 'option1':
alert( 'user clicked option1' );
break;
case 'option2':
alert( 'user clicked option2' );
break;
case 'option3':
alert( 'user clicked option3' );
break;
}
}
function optionTabs(){
var optionTabs = document.querySelectorAll( 'div' ),
i = 0;
for( i; i < optionTabs.length; i++ ){
optionTabs[ i ].addEventListener( 'click', optionClicked );
}
}
optionTabs();
html {
background-color: #eee;
font-family: sans-serif;
}
div {
cursor: pointer;
margin: 1rem;
padding: 1rem;
background-color: #fff;
letter-spacing: 0.05rem;
}
div:hover {
background-color: #555;
color: #eee;
}
<div class="option1 more">option 1</div>
<div class="option2 classes">option 2</div>
<div class="option3 here">option 3</div>
Solution 3:[3]
You have to use this.classList.contains, that returns a boolean.
function optionClicked(){
switch(true){
case this.classList.contains('option1'):
alert( 'user clicked option1' );
break;
case this.classList.contains('option2'):
alert( 'user clicked option2' );
break;
case this.classList.contains('option3'):
alert( 'user clicked option3' );
break;
}
}
Solution 4:[4]
I did something a bit different than a switch. Created an array full of your options and filtered out the result only if the element's classes match an option in the options array.
You would need to then do your check on the filtered result. Ori's answer is a more straight to the point.
function optionClicked(){
var classes = this.className.split(' '),
options = ['option1', 'option2', 'option3'];
var clickedOption = classes.filter(function(c) {
return options.indexOf(c) >= 0;
});
alert(clickedOption)
}
function optionTabs(){
var optionTabs = document.querySelectorAll( 'div' ),
i = 0;
for( i; i < optionTabs.length; i++ ){
optionTabs[ i ].addEventListener( 'click', optionClicked );
}
}
optionTabs();
html {
background-color: #eee;
font-family: sans-serif;
}
div {
cursor: pointer;
margin: 1rem;
padding: 1rem;
background-color: #fff;
letter-spacing: 0.05rem;
}
div:hover {
background-color: #555;
color: #eee;
}
<div class="more option1">option 1</div>
<div class="option2 classes">option 2</div>
<div class="option3 here">option 3</div>
Solution 5:[5]
Adding this to your optionClicked() function should work!
function optionClicked(){
let classNames = this.className.split(" ")
className = classNames.find(
function (val){
return /option\d/.test(val)
}
)
// switch
}
Full Function
function optionClicked(){
let classNames = this.className.split(" ")
className = classNames.find(
function (val){
return /option\d/.test(val)
}
)
switch( className ){
case 'option1':
alert( 'option1' );
break;
case 'option2':
alert( 'option2' );
break;
case 'option3':
alert( 'option3' );
break;
}
}
function optionTabs(){
var optionTabs = document.querySelectorAll( 'div' ),
i = 0;
for( i; i < optionTabs.length; i++ ){
optionTabs[ i ].addEventListener( 'click', optionClicked );
}
}
optionTabs();
Solution 6:[6]
classList has a parameter value and instead of creating an array or using switch(true), you can simply check for the existence of a string:
switch (element.classList.value) {
case 'new-elem' :
console.log(1);
break;
case 'data-elem':
console.log(2);
break;
}
Solution 7:[7]
In my opinion, the switch statement is cluttering the code as it's likely you will always use break statements immediately following every case.
Instead to not repeat yourself, you can make an array of handlers per each class name (by splitting the classList.value string by whitespace) and check if there's an existing handler for each class name.
const handlers = {
'option1': () => alert('User clicked option1'),
'option2': () => alert('User clicked option2'),
'option3': () => alert('User clicked option3'),
};
this.className.value.split(/\s+/).forEach(className => handlers[className]?.());
Note: This isn't precisely logically equivalent, but given the likelihood that the presence of one option excludes the presence of all the other options, then this is a cleaner and more succinct way to go.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Ori Drori |
| Solution 3 | Alan Grosz |
| Solution 4 | Wild Beard |
| Solution 5 | Cristobal Ignacio |
| Solution 6 | Christian |
| Solution 7 | Steven |
