Event Handlers and Logic Don't Mix
- 10/20/2018
- ·
- #javascript

We talk event handling, and out comes the
question: “Isn’t it redundant to call it onKeydown
?”
I suppose it is. onKeydown
hints at what should happen before the function is
called (though we’ll need to inspect the call-site to confirm that hint), but
may give us next to nothing about what the method actually does. They’re howling
in outrage at the School of Useful Names.
In the particular case of event handlers, though, this sort of name seems fine. Compared with implementing the handler as an anonymous closure, naming the method will enable reuse and help identify it in stack traces. We’re already ahead, there.
But the second, bigger reason for a stupid name like onKeydown
is to
emphasize what handlers aren’t: business logic.
Presentation & Logic
Whether events originate from a user interface or another unit of our system, they’re input here. Without rigorous guarantees about their shape and content, handling them safely means validating, sanitizing, and extracting domain objects for consumption by the rest of the system. Only after we’ve “accepted” an event should we delegate to business logic.
Putting that into code:
function onKeydown (e) {
if (!(e.keyCode && typeof e.keyCode === 'number')) {
// Caller passed an invalid event. Panic.
throw new Error('Event missing numeric .keyCode');
} else if (e.keyCode < 65 || e.keyCode > 90) {
// Key doesn't match [A-Z]. Ignore it.
return;
}
// Cast type => string
const char = String.fromCharCode(e.keyCode);
// Delegate "accepted" input to business logic
recordCharacter(char);
}
Event handlers are great places to, well, handle events. If we stick to that single responsibility, leaving business logic for another, nicely named function, we’ll have an easier time verifying that validation is behaving as intended. Plus, we decouple the underlying business logic: if multiple handlers need keyboard input, we can write a wrapper to filter incoming events and only forward “acceptable” ones:
function alphaHandler (handler) {
return function (e) {
if (!(e.keyCode && typeof e.keyCode === 'number')) {
throw new Error('Event missing numeric .keyCode');
} else if (e.keyCode < 65 || e.keyCode > 90) {
return;
}
return handler(String.fromCharCode(e.keyCode)char);
};
}
At this point, we can create any event handler we need by composing validation and business logic:
const onKeydown = alphaHandler(recordCharacter);
It’s still onKeydown
, and it’s still a stupid name. For a stupid function.
Exactly as it should be.