In the real world, we deal with some really weird problems. I had to. You had to/will have to. It is inevitable. One fine day, I was asked to add a feature on an existing interface. It was starting from a simple checkbox with some state update. Sounds simple.
If you want to read up a little on event propagation in JS, you can check out Part 1 of this article (shameless self plugging ^-^; ).
I added the checkbox markup and it was rendering on the front-end alright. I clicked on the checkbox and there was nothing. No click event fired. The checkbox which I took for granted for years — it wasn’t… well checking.
What could have been the problem? Yeah I know it’s pretty much right there but the code was pretty complicated in my case… please believe me. The above example is just a snippet of that huge code to narrow down and work on the actual problem.
If some event is not working as it is supposed to, well it is usually a rogue
preventDefault() in the code. Check for that first. In my case, luckily, it was.
Since its a legacy code (which will be the case in the real world), you might not be able to remove the
preventDefault() and you'll have to workaround that. So obviously, you will add code to handle the event on click of the checkbox like this -
We check for the target element’s ID and then toggle the state of the checkbox. This should do it right? If you try to replicate this, you’ll see that it won’t.
If you console log the state of checkbox, you’ll see that it returns
true but that doesn't reflect on the front-end. Keep clicking on the checkbox and it keeps returning
true. But why doesn't the state change?
If you look at the code, there is a preventDefault on the parent (body). From what we know of Event Bubbling, the click event on the checkbox bubbles up on the body and the body then hits preventDefault call and cancels the action. During any point in the event flow, browser finds a preventDefault, the active event chain, if cancelable, is cancelled. So all the events are cancelled, though for some reason the checked state of the box is temporarily changed to true but upon the event chain cancellation, it is reset to false.
That was the problem. Now for the solution, I found a hack around this using
setTimeout(). The action I want to perform is set to happen after the current event chain is processed (here, cancelled) and then my checkbox thing happens. See this -
Now using the
setTimeout() with 0 delay value, the action to update the checked state is kept in the event loop as soon as the active chain is cancelled. Your code should work!
El Psy Congroo!