Dan Denney illustration

Stumbling Through Learning About Event Listeners

Disclaimer: In this post, I am sharing something that I've been learning. It's in no way a how-to and in fact I'd love feedback on better ways to do what I've done.

I had been progressing pretty well lately in learning vanilla JS and it felt awesome. Then I hit a wall in doing something that I thought was straight forward. I ended up putting about 5-6 hours into grokking how to get a value out of an event listener, that time being split between attempts, googling, reading Stack Overflows, reading the docs, pairing with a coworker, and maybe an hour sitting like this.

(If this, then that) * 999

The fun part of front-end development is that there are likely 999 ways to solve the problem that I was facing. Having chosen one, I then tried about 423 ways to achieve it before getting it to work. If I wasn’t so focused on improving my skills I might have switched away to a different solution, but I had to know that I could do this.

A reduced test case

The original problem was that I wanted to validate 2 datetime-local inputs. If the second datetime value is after the first, then submit a form to Firebase. The problem with sharing that for help was that there was so much unnecessary code (the date conversions, Firebase submission, etc.)

In this pen I simplified it and named the variables and functions in a way to describe what I was trying to achieve because I knew I needed help.

To make it simple, this is comparing the value of two selects with numbers from 1-4. I knew how to get those values and compare them within the event listener, but I didn’t know how to get that value to bubble up to the parent function. (I wanted to do this because I knew I could then conditionally submit the form based on the true/false result of the comparison.) It turns out that you can’t, at least not directly. I had stumbled into some complex territory, obliviously.

Reiterating from above, I could have opted to do something different like disable/enable the submit button from the event listeners. However, this became more about learning how to get that value out of there because it seems like an important concept to understand.

A solution

I know about 422 ways that you cannot return a value out of an event listener and use it in a separate function. I now know one way that you can and I’m sharing it here. It’s not elegant and it may not even be "right", but it works. Hopefully a few people more advanced than I am will chime in with 1 of the 999 other ways that you can do this.

The “solution” was creating a retrieval function that can be shared between the two. The least technical explanation of this ever is that it is necessary because nothing is “listening” for updates from the event listener. I was trying to update the parent function or variables in it, but that can’t work without calling the function again.

As a workaround, I created a retrieval function to sit in the middle of the two. It runs when the select event happens and its value is then updated. Since that function now has an updated value, it can be used as a check on whether or not to proceed in a separate function.

In this example, if the second select value is greater than the first, then sending should be allowed. If not, then it shouldn’t. 5-6 hours and a blog post later, the “simple” thing that I was trying to do is working.

Avatar
Join the discussion…


  • in this conversation
      Media preview placeholder
      Log in with
      or sign up with Disqus or pick a name

      Disqus is a discussion network

      • Disqus never moderates or censors. The rules on this community are its own.
      • Don't be a jerk or do anything illegal. Everything is easier that way.

      Read full terms and conditions

      • Avatar

        I always enjoy reading your “learning” posts. From one JS newbie to another: it usually simplifies things when you write code that’s as stateless as possible. I.e., try not to keep track of data if you can help it. Especially when that data is “computed” (reliant on other data). Otherwise, you have to deal with scoping and updating it every time it changes or its dependent data sources change.

        In your example it might make life easier if you never saved the value of (#select-two > #select-one), and simply just made an outside function that returned the comparison of those two values. You could call that function from within any event listener you needed to ('click', 'blur', 'change', etc.), and it’d always be accessible and correct. Bonus points if you left the query selectors in the listeners, and just made a pure math comparison function you could reuse for all sorts of things.

        • Avatar

          Ohh, interesting problem. I might be off on this, but I think your `isTrueOrFalse` variable is leaking to the `window` variable here, since it's not defined elsewhere, which is why you're able to access it like this. If this entire code block was wrapped in a closure that would prevent it from using `window` though ( http://codepen.io/adamfortu... ) and that's also what Rails does for each separate file anyways.

          My default way to do something like this (not the right way by any means, but the way I'm most familiar with), is using a class, then using `bind` to allow the `this` function within the event listener to be the instance of the class. That allows you to think of the individual listeners written in the same way as the rest of the methods. (ex: http://codepen.io/adamfortu... )

            • Avatar

              Shiiiiiit. You're totally right, thank you. Because I didn't declare the scope with a var, that goes up to the window. I might as well have just created a global var to update.

              Thank you for your examples, too. I haven't used bind since before my jQuery days, so I need to brush up on that.