Building in validation to much-select

The Problem

One of the crucial features I wanted <much-select> to support is value transformation and validation. This is important for configuring <much-select> to allow users to input “custom” values (not just the predefined options in the list) but you still need some guard rails on the values the user can enter. Accomplishing this through standard web APIs proved to be a daunting task. I tried some different things and I’m going to describe what I came up with and why.

The Solution

There are things in here that feel like “hacks” though, so if, by the time you find this article some time has past, it’s quite possible the <much-select> APIs will have changed for the better. I sure hope so anyway.

The transformation-validation Slot

Adding an API for transformation and validation was going to be too complicated for simple key/value pairs, like the sort that are easily expressed in HTML attributes. I have stuffed complex data into attributes before with JSON and HTML entity escaping. However in this case an element with a slot="transformation-validation" attribute on it with JSON in it felt a bit better. I don’t love this though. I don’t know of any standard HTML elements that do anything like this.

Ideally the tag would be semantic, so a <script type="application/json"> but Elm does not let you do that for security reasons, so I made sure using a <span> tag would also work.

The format of the configuration in there is… readable, it’s a list of transformers and then a list of validators. This reflects the order of operations, that the transformers run first and then validators.

{
  "transformers": [
    {
      "name": "lowercase"
    }
  ],
  "validators": [
    {
      "name": "no-white-space",
      "level": "error",
      "message": "Spaces are not allow for custom fruit."
    },
    {
      "name": "minimum-length",
      "level": "silent",
      "minimum-length": 3,
      "message": "The minimum length is 3."
    }
  ]
}

I suppose if I wanted an even richer API I could perform the transformations and validations in the order they are defined in the JSON. I’ll have to think about that.

Events (Custom Validation)

The goal is to have several built in transformers and validators, and if none of those will do, there’s the ability to do custom validation. This is risky though, you need to have JavaScript that’s ready to handle the events and respond with feedback. If (as a consumer of <much-select>) you fail to do that, things will not work right.

Once <much-select> is set with a custom validator and user input is stable, the transformation and validation process kicks off.

All the built-in transformers and validators are launched and the UI updates to show the results.

If a custom validator is in place, <much-select> fires off a customValidateRequest event. It then hangs tight for a change in the DOM. A mutation observer keeps an eye on a slot named custom-validation-result. MuchSelect looks for JSON appearing here with a list of relevant fields and their pass/fail status in response to the custom validation request. If they have failed an error message can be supplied.

This allows you to do things like call out to an RESAT API for the validation. For instance, if you need a REST API to tell you if a value is OK to be used. For instance if the value needs to be unique.

This API still feels hack-y and maybe not a great experience to hand roll your self, but hopefully, if you need to use the custom validation feature in <much-select> you can use a library that will make this API easier to work with.

Built in Transformers and Validators

At the time of writing this, I’ve got a few transformers and validators up and running. I’ll be adding more as I find the need or get requests.

Transformers:

  • lowercase

Validators:

  • no white space
  • minimum length (this includes the ability to set the minimum length)

I’ve also thrown in a way to set the “level” of error messages. The thinking here is to maybe just give users a heads-up rather than stopping them dead in their tracks. So, let’s say you’re using the lowercase transformer and the user tries to sneak in some uppercase letters. You can warn them that their input will be accepted, but it’s going to end up looking a bit different from what they typed in.