Update to elm-validation library

I am updating my input validation library to better handle cases where you want to run validation “onBlur” and not “onInput”, in response to this issue: https://github.com/ericgj/elm-validation/issues/3

Essentially, it means adding a state called Unvalidated String – when input is happening but you haven’t yet run validation on it.

The question arose whether then we need an Initial (empty) state, since Initial could be modelled as Unvalidated "".

My view is it may be useful to distinguish cases where a user starts entering and then deletes their input, versus a truly unedited initial state. (Also, given the structure is monadic it seems odd not to have a true empty state, although I guess I could rewrite initial = Unvalidated "".)

But, it was objected that this would force users to handle two states that in most cases are for practical purposes the same. The data structure is not opaque so potentially people would be caseing on it. (Although I think I give enough basic functions you really shouldn’t need to, IMO.)

Anyway, long story short, if anyone else uses this library now or would like to use it, let me know what you think, either here or on the github issue.

I’ve added a branch which has distinct Initial and Unvalidated String states, and an example if you are curious what it would look like.

1 Like

Hello Eric

We recently were having a similar discussion on Slack, and I mentioned that I considered using your library for my project but because there was no way to handle state of the input without validating it, I created my own type:

type Validation value
    = Pristine String
    | Dirty String
    | Invalid String String
    | Valid value

I used this type to model the different state of my input field. Pristine can hold an initial value. As soon as the user touches the input, I changed it to Dirty with the new value. This is excellent when you have a required field that the user just jumped over. An empty String by itself can’t differentiate that it is empty because that’s the initial value or not.

Since I don’t want to pester my user with errors as they’re typing, I delay the validation until a second after they finish writing. At that moment, I pass it through my validator and it returns either Valid or Invalid depending on the result.

At least for me, it makes sense to distinguish between the state before and after validation, and this type works for me.

Hi Chris,

I like how you modelled this, but to be splitting hairs, Pristine should hold a value rather than a String. I also see how in your case (validation with a timer) you need to distinguish between Pristine "" and Dirty "".

Hi @la-yumba :wave:

The reason why I would avoid placing a value instead of a String in the Pristine constructor is because there are some values that can’t be created directly.

Let’s say you want to ask the user to input a prime number, and to model that you decide to use the Prime type in Fresheyeball/elm-restrict-number. You can’t create this value directly, since the only constructor offered returns a Maybe Prime. If you had another Prime to provide as a default, there would be no problem, but in this example there isn’t.

On the other hand, if you want to provide 3 as a default prime number, you set Pristine "3", and when it is time to validate it, if the user did not change the value, it will turn to Valid (Prime 3), otherwise if the user provided a "4", it will turn into an Invalid "Please provide a prime number" "4".

So, actually I meant that Pristine should wrap a Maybe value - because
of course your form does not need to provide an initial value. The idea
is that if validation and conversion produce a value, then if you provide
an initial value it should be valid value. Otherwise, your type allows
the programmer to create a Validation Prime of, say, Pristine "hello".
This is why Pristine Maybe value would create a more consistent interface
for the programmer to code to.

Having said that, I still think that for most application, distinguishing
between Pristine and Dirty is a bit overkill. :slight_smile: