Reputation: 39
I am making an application according to the youtube tutorial. I already know what the correct solution looks like, but I don't know why such a code does not work. It is only executed once. I check 'Inspector' in the browser and there it shows that the second div got active class, but the second click doesn't work.
document.querySelector('.emoji').addEventListener('click', function() {
document.querySelector('.open').classList.toggle('active');
document.querySelector('.closed').classList.toggle('active');
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.emoji {
text-align: center;
font-size: 20rem;
cursor: pointer;
display: none;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.active {
display: block;
}
<!-- emoji no evil 🙈
emoji monkey 🐵 -->
<div class="emoji open active">🙉</div>
<div class="emoji closed">🙈</div>
And now why this solution doesn't work?
I think that i have 2 elements with 'emoji' class so this should work. Today I tried create calculator app and has same problem . Only first button works when i clicked on it. I know that correct solution is :
document.querySelector('.open').addEventListener('click', function () {
document.querySelector('.open').classList.toggle('active');
document.querySelector('.closed').classList.toggle('active');
});
document.querySelector('.closed').addEventListener('click', function () {
document.querySelector('.closed').classList.toggle('active');
document.querySelector('.open').classList.toggle('active');
});
But i dont understand why first solution is wrong. Please could you explain.
Upvotes: 2
Views: 110
Reputation: 40842
document.querySelector
returns only one element, which is the first element matching the selector.
One way you could target that problem is to wrap both elements, into one container and listen for the click on that element:
document.querySelector('.emoji-toggle').addEventListener('click', function() {
document.querySelector('.open').classList.toggle('active');
document.querySelector('.closed').classList.toggle('active');
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.emoji {
text-align: center;
font-size: 20rem;
cursor: pointer;
display: none;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.active {
display: block;
}
<div class="emoji-toggle">
<div class="emoji open active">🙉</div>
<div class="emoji closed">🙈</div>
</div>
Or to use event delegation:
document.addEventListener('click', function(e) {
if (e.target.matches('.emoji')) {
document.querySelector('.open').classList.toggle('active');
document.querySelector('.closed').classList.toggle('active');
}
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.emoji {
text-align: center;
font-size: 20rem;
cursor: pointer;
display: none;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.active {
display: block;
}
<div class="emoji open active">🙉</div>
<div class="emoji closed">🙈</div>
If it is something like a checkbox you probably want to use the first approach.
Depending on what you want to do you don't even need JavaScript for that:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.emoji {
text-align: center;
font-size: 20rem;
cursor: pointer;
display: none;
}
#mycheckbox:checked + label .open {
display: block;
}
#mycheckbox:not(:checked) + label .closed {
display: block;
}
#mycheckbox {
display: none;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
<input type="checkbox" id="mycheckbox">
<label for="mycheckbox">
<div class="emoji open">🙉</div>
<div class="emoji closed">🙈</div>
</label>
If you play around with the placement of the input
element, and the selectors, and the placement of the label element, and utilizing transitions and animations you can do mobile menus, different font sizes, and switching of the color theme, without any JavaScript.
Upvotes: 3
Reputation: 5767
querySelector
only selects the first occurance. If you want to select both buttons you could use querySelectorAll
or getElementsByClassName
and iterate over them with a for loop.
Working example:
let buttons = document.querySelectorAll('.emoji');
for (i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function() {
document.querySelector('.open').classList.toggle('active');
document.querySelector('.closed').classList.toggle('active');
});
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.emoji {
text-align: center;
font-size: 20rem;
cursor: pointer;
display: none;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.active {
display: block;
}
<div class="emoji open active">🙉</div>
<div class="emoji closed">🙈</div>
Upvotes: 2