0

I want to toggle a css class on all elements with the same class, on click of another element.

I had it working with jQuery but need to switch to pure JavaScript.

The jQuery version that works:

$(function() {
  $("#logo").click(function() {
    $(".grey").toggleClass("white", 1000);
    $(".red").toggleClass("orange", 1000);
  });
});

When you click on the element with id="logo", everything with class="grey" toggles white class and everything with class="red" toggles orange.

Update with new problem!

I'm using @Vektor's code which works well — except on the iPhone 5 where nothing happens. (It works in my iPhone 12 and 7.) Simplified code for trials:

<body>
    
<div id="logo"  class="grey"><p class="red">Hello.</p>
</div>

<script>

    const logo = document.getElementById('logo');
    
    logo.addEventListener('click', () => {
        const grey = document.querySelectorAll('.grey');
        const red = document.querySelectorAll('.red');
        grey.forEach(e => e.classList.toggle('white'));
        red.forEach(e => e.classList.toggle('orange'));
    }, false);
</script>
</body>
body{background-color: #000000;}
div#logo{
  position:fixed;
  top:0;
  left:0;
  height: 100vh;
  width:30vw;
  cursor: pointer;
}
.red{background-color:#4C0000;}
.orange{background-color:#d69215}
.grey{background-color:#485055;}
.white{background-color:white;}

I read adding cursor:pointer would fix JavaScript not functioning on non-traditional clickable elements for older iPhone browsers. It didn't.

nobi-wan
  • 1
  • 1
  • 3
  • Where is your own attempt? – connexo Jan 08 '22 at 09:24
  • 1
    The last paragraph (`I've googled … Thank you in advance.`) does not add any insight to your problem. Instead of that paragraph you should have shown what you have tried and explain what problems you had with your approach – t.niese Jan 08 '22 at 09:25
  • My own best attempt (that toggled only on one element) was long deleted and replaced with subsequent worse attempts and probably embarrassing desperate hacks, also deleted. – nobi-wan Jan 08 '22 at 11:54
  • Use an anchor or button tag for the logo. – Vektor Jan 12 '22 at 20:54

4 Answers4

1

first grab the "id". Then Listen for a "click" event on that. When click occurs grab the all "white" class elements first. "queryselectorAll" returns an array-like NodeList, so you can use "forEach" array method on that. Then iterate the all elements one by one. Same logic goes for "red" class elements.

 let  logo = document.getElementById('logo');

    logo.addEventListener('click', ()=>{
        let grey = document.querySelectorAll('.grey');
        grey.forEach((e)=>{
            e.classList.toggle('white')
        })
        let red = document.querySelectorAll('.red');
        red.forEach((e)=>{
            e.classList.toggle('orange')
        })
    })
connexo
  • 53,704
  • 14
  • 91
  • 128
Arijit Maiti
  • 99
  • 2
  • 8
  • 1
    Please add some explanation to your otherwise good answer. – connexo Jan 08 '22 at 09:22
  • first grab the "id". Then Listen a "click" event on that. After listening grab the all "white" class first. "queryselectorAll" returns a node like array. so you can use "forEach" loop on that. then iterates the all elements one by one. Same logic goes for "red" classes. – Arijit Maiti Jan 08 '22 at 09:32
  • I cant find anything wrong in my code. If you got some issue mention that. I'm new here actually – Arijit Maiti Jan 08 '22 at 09:33
  • 1
    To make a good answer you should not only show code without any explanation. And the explanation should be in the answer itself und not added as comment. – t.niese Jan 08 '22 at 09:36
  • This worked just dandy — thank you — but @Vektor's looks more elegant so I'm using that... though there is a new issue that I've asked him(?) about. – nobi-wan Jan 10 '22 at 13:55
1

Firstly, select the logo element by its id attribute. Register a click event listener on it to trigger the procedure. The event handler function will select all the elements containing the grey & red class names producing a list of nodes, iterate over them, and for each of those elements, toggle the white & orange class names in the list of classes.

const logo = document.getElementById('logo');

logo.addEventListener('click', () => {
    const grey = document.querySelectorAll('.grey');
    const red = document.querySelectorAll('.red');
    grey.forEach(e => e.classList.toggle('white'));
    red.forEach(e => e.classList.toggle('orange'));
}, false);
body {
  background-color: #666;
}

.grey {
  color: #bbb;
}

.red {
  color: red;
}

.white {
  color: white;
}

.orange {
  color: orange;
}
<button id="logo">LOGO!</button>

<p class="grey">Hello World</p>
<p class="red">Hello World</p>
<p class="grey">Hello World</p>
<p class="red">Hello World</p>
<p class="grey">Hello World</p>

I hope this solves your problem.

Update

As per request by OP, I've added these updates to address the issue regarding the click event not being fired on older iPhone versions (namely the iPhone 5) in the above solution. Because I don't have access to those devices, I can't guarantee the viability of the following suggestions.

<a href="javascript:handleClick();">LOGO1!</a>
<a href="#" onclick="handleClick(); return false;">LOGO2!</a>
<a href="#" ontouchstart="handleClick();">LOGO3!</a>
const handleClick = function handleClick() {
    const grey = document.querySelectorAll('.grey');
    const red = document.querySelectorAll('.red');
    grey.forEach(e => e.classList.toggle('white'));
    red.forEach(e => e.classList.toggle('orange'));
}
Vektor
  • 697
  • 5
  • 14
  • This works great. Thank you. But I've since had to make two elements able to trigger the switch, so I made that thing id="logov" and duplicated your script therein switching "logo" for "logov". Works fine... except on iPhone 5, and I assume other (I'm guessing not-current) platforms. Any clue as to why that would be? – nobi-wan Jan 10 '22 at 13:44
  • Note I'm doing this within and to inline svg. Just noted an `a href` within doesn't work on the older iPhone either. – nobi-wan Jan 10 '22 at 15:14
  • I'm not sure I'm following, can you update the question post with the code? What browser are you running on the iPhone 5, or are you referring to the emulator in chrome? My example is using a button, it could be that your anchor tag is triggering a page refresh on the older devices, but that's just my speculation... – Vektor Jan 10 '22 at 22:01
  • On further investigation I reckon it's an issue with click events within SVGs (they don't work) on earlier iOSs. Apparently jQuery got around it, and there are some fiddles for JS which don't seem like they can be applied to this... – nobi-wan Jan 11 '22 at 18:49
  • I've added the new problem to the original Q – nobi-wan Jan 12 '22 at 16:34
  • @nobi-wan you can test my update – Vektor Jan 12 '22 at 20:53
  • `LOGO` works on both logo clickers on all the old iPhones I have. I believe everything works as it should now. Thank you so much. – nobi-wan Jan 13 '22 at 09:38
  • @nobi-wan okay, I'm glad to help. You can accept the answer if it resolves your issues. – Vektor Jan 13 '22 at 17:42
0

You can get an element by its class and then operate on it:

document.getElementById('logo').addEventListener('click', function(){
  var redElements = document.getElementsByClassName('red');
  Array.from(redElements).forEach(el => el.classList.toggle('orange'));

  var greyElements = document.getElementsByClassName('grey');
  Array.from(greyElements).forEach(el => el.classList.toggle('white'));
});
Marco
  • 22,856
  • 9
  • 75
  • 124
  • `document.querySelector`will only find the first match. – connexo Jan 08 '22 at 09:20
  • Yeah, noticed this myself. Fixed – Marco Jan 08 '22 at 09:31
  • `for (const redElement of redElements)`saves you the `Array.from` hassle **and** makes the code more readable. It also doesn't require a predicate like `forEach` does. – connexo Jan 08 '22 at 09:43
  • In was under the impression that for of wouldnt work, since HTMLCollection is not iterable out of the box. – Marco Jan 08 '22 at 10:02
  • That is the whole point, it **is** iterable out of the box, it just doesn't naturally implement `forEach` on its prototype. See https://stackoverflow.com/questions/41758982/can-htmlcollections-be-iterated-with-for-of-symbol-iterator – connexo Jan 08 '22 at 10:04
  • Ah, learned something new again. Thanks. – Marco Jan 08 '22 at 10:12
-3

simplification of javascript is jquery so dont need to do it in hard way friend.

    var grey = document.getElementByClassName("grey");
   grey.classList.toggle("white");

   
  • 1
    There is no `getElementByClass` on `document`. – connexo Jan 08 '22 at 09:19
  • 1
    The method is called `getElementsByClassName`, and It returns a live HTMLCollection, so you'll need to fix the name and iterate on it to be able to perform something on each element. Also, it would be nice if you take your time to write and format the answer in a cleaner way. – Leo Jan 08 '22 at 09:59