Home > database >  Cannot toggle class to label in forms
Cannot toggle class to label in forms

Time:08-06

I was working on a modal component in Angular and was trying to toggle a class state on a custom input checkbox on clicking on the label, but it didn't work, I thought it was something with material or else with Angular, but also tried with plain HTML and vanilla JS and it does not allow to change or toggle a class in the label. How could this be? Is there something I am missing with the label click behavior? If you click directly on the input it adds the class 'active' but if clicked the 'M' it doesn't. I am hiding the input from the view since I am styling it to look different.

Here is a piece of code for trying here:

window.addEventListener('load', function() {
  let elems = document.querySelectorAll('.form-check-label');
  elems.forEach((e) => e.addEventListener('click', function() {
    console.log(e.classList);
  }, false));
}, false);

function checkInput(elem) {
  let checkMark = elem.querySelector('input');
  checkMark.checked = !checkMark.checked;
}
.form-check-label {
  cursor: pointer;
}
<label 
onClick = "this.classList.toggle('active');"
 
for="Monday">
  <input 
   
  type="checkbox" 
  id="Monday" 
  value="Monday" />
  <span >
   M
  </span>
</label>

<br />
<br />

<div 
onClick = "this.classList.toggle('active');checkInput(this);"
 
>
  <input 
   
  type="checkbox" 
  value="Monday" />
  <span >
   M
  </span>
</div>

If I change the label for a div, then it works. You can check the class state change in the browser console.

CodePudding user response:

This is a interesting case which seems to be related to the behaviour of input controlled by label. It can be observed that the click on label generate actually 2 click events, first coming from span and second (which seems to be a browser synthetic event nevertheless "real") from input, which sets the focus on input element, this is most obvious when using a text type input. So, the first click sets the class while the second removes it, that happens almost instantaneous.

As a simple solution is to discard the click event generated by input with event.stopPropagation(), although it will disable a real click on checkbox:

window.addEventListener('load', function() {
  let elems = document.querySelectorAll('.form-check-label');
  elems.forEach((e) => e.addEventListener('click', function() {
    console.log(e);
  }, false));
}, false);

function checkInput(elem) {
  let checkMark = elem.querySelector('input');
  checkMark.checked = !checkMark.checked;
}
.form-check-label {
  cursor: pointer;
}
<label 
onClick = "this.classList.toggle('active');"
 
for="Monday">
  <input 
  onClick = "event.stopPropagation();"
   
  type="checkbox" 
  id="Monday" 
  value="Monday" />
  <span >
   M
  </span>
</label>

<br />
<br />

<div 
onClick = "this.classList.toggle('active');checkInput(this);"
 
>
  <input 
   
  type="checkbox" 
  value="Monday" />
  <span >
   M
  </span>
</div>

CodePudding user response:

I suggest that you use the checked state of the checkbox instead of controlling the checked state manually.

This is different when using Angular or React, but then you most likely control the checked state instead.

let elems = document.querySelectorAll('.form-check-label > input[type="checkbox"]');
elems.forEach((e) => e.addEventListener('change', function() {
  if (e.checked) {
    e.parentElement.classList.add('active');
  } else {
    e.parentElement.classList.remove('active');
  }
}, false));
.form-check-label {
  cursor: pointer;
}

.form-check-label.active {
  color: red;
}
<label  for="Monday">
  <input
     
    type="checkbox" 
    id="Monday" 
    value="Monday" />
    <span >
      M
    </span>
</label>

  • Related