I intentionally used subscriptions instead of Task.sleep, as I believe newcomers have a better understanding as to what a subscription does opposed to what a task does.
If you have any additional insight or useful resources please tell me. Also, I will link this topic in my elm-cookbook; So here’s a quick to all my future readers.
I had to implement a debounce recently, and I wrote it exactly the way you did (except there was no ambiguity about which field needed validation, so it was just a countDown : Maybe Int).
The implementation you have has the potential to throw away input data. Basically, if the input in the second field happens within the debounce interval, the old input is lost as it is being replaced by the new input.
You can see this bug/issue if you either increase the msUntilTimout to something larger that would allow you to type in the name field, switch to the password field and type something (the data inputed in the Name field is lost).
Of course, if you type fast and use tab to switch between fields you can reproduce the bug even with 500 ms.
Other than that, the implementation is elegant. I like it.
To avoid the problems mentioned by @pdamoc, on my current project I’m passing all the info into the messages. This allows each field to be debounced independently (and possibly in parallel).
type Msg
= InputOccurred FieldName String
| TimePassed FieldName String
It might be hard to vary the messages with a subscription though. I’m using a task on my project.
As a crazy idea, you could monkey patch the underlying event system. This could be wrapped up in elm so that you have a nice interface to hide the evil JS.