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.
>Solution :
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>