Add additional validations on the form element, beyond those that can be specified on an individual field level.
<form be-formidable='{
"invalidIf":[
{
"noneOf": ["@url", "@file"],
"invalidCssClass": "no-url-or-file-selected"
}
]
}'>
<label>
URL:
<input name=url id=url type=url>
</label>
<label>
File:
<input name=file id=file type=file>
</label>
</form>
Attaching this enhancement / behavior results in overriding the checkValidity() method of the form element. Calls to checkValidity has the added side-effect of modifying css classes on the form element. If the validations fail, css class "invalid" is added to the form element. Otherwise "valid" is added. In addition, if the "invalidCssClass" property is specified, it will get applied to the form element, or removed, depending on the validation.
It is easy to define a custom, (shorter) name for less formal environments. be-formidable is the canonical name, but by referencing an alternative registration file we can use, for example:
<form 🥷🏾='{
"invalidIf":[
{
"noneOf": ["@url", "@file"],
"invalidCssClass": "no-url-or-file-selected"
}
]
}'>
<div class=instructions>Please Select a url or a file</div>
<label>
URL:
<input name=url id=url type=url>
</label>
<label>
File:
<input name=file id=file type=file>
</label>
</form>
It could be argued that validOnlyIf/oneOf is clearer than invalidIf/noneOf. Here's why we chose the more counterintuitive approach:
This component prefers the "innocent until proven guilty" way of thinking, because it feels a bit truer to what it is actually doing, and may more effectively alert the developer to the fact that the form will be considered valid until the be-formidable behavior / enhancement is attached. Before then, it might be prudent to hide/disable any submit buttons, or even hide or obscure the entire form.
Editing JSON-in-html can be rather error prone. A VS Code extension is available to help with that, and is compatible with web versions of VSCode.
And in practice, it is also quite ergonomic to edit these types of attributes in a *.mjs file that executes in (no)de(no) as the file changes, and compiles to an html file via the be-importing compiler, for example. This allows the attributes to be editable with JS-like syntax. Typescript 4.6 supports compiling mts to mjs files, which then allows typing of the attributes. Examples of this in practice are:
The specifier for which elements to monitor follows the DSS syntax.
By default, the "value" property is what is used on the element when it is checked for truthiness.
To specify an alternative property to check:
<form be-formidable='{
"invalidIf":[
{
"noneOf": ["@keysInPocket.checked", "@havePhone.checked"],
"invalidCssClass": "not-ready-to-go-out"
}
]
}'>
<div class=instructions>
Please take your keys, or at least a phone to call a locksmith.
</div>
<label>
<input name=keysInPocket type=checkbox>
I have keys in my pocket
</label>
<label>
<input name=havePhone type=checkbox>
I have a phone
</label>
</form>
So this syntax is not compatible with form elements that use "." in the name. If encountering a scenario where "." may be in the name, we need to be a bit more verbose:
<form be-formidable='{
"invalidIf":[
{
"noneOf": [
{
"name": "keys.in.pocket",
"prop": "checked"
},
{
"name": "have.phone",
"prop": "checked"
}
],
"instructions": "Please take your keys, or at least a phone to call for a locksmith.",
"invalidCssClass": "Not ready to go out."
}
]
}'>
...
</form>
The rules so far have essentially been providing support for the "required" attribute, but for groups of form elements. But there are other validations that form fields support (min, max, pattern, etc).
Support for such criteria is provided. For example with min:
<form be-formidable='{
"invalidIf":[
{
"noneOf": [
{
"name": "firstCustomer Age",
"min": 17,
},
{
"name": "secondCustomer Age",
"min": 17,
},
{
"name": "thirdCustomer Age",
"min": 17,
},
],
"instructions": "No one under the age of 17 is permitted to watch this movie without being accompanied by an adult or guardian"
}
]
}'>
...
</form>
NotEquals
<form be-formidable='{
"validOnlyIf":[
{
"atLeastOneOf": [
{
"name": "firstCustomer Age",
"min": 17,
},
{
"name": "secondCustomer Age",
"min": 17,
},
{
"name": "thirdCustomer Age",
"min": 17,
},
],
"equals": [
{
"name": "hiddenCalculatedField"
},
{
"name": "payment"
}
]
"instructions": "No one under the age of 17 is permitted to watch this movie without being accompanied by an adult or guardian"
}
]
}'>
...
</form>
<form be-formidable='{
"invalidIf":[
{
"noneOf": [{
"find": ".my-form-element-group",
"prop": "checked"
}],
}
]
}'>
...
</form>
"invalidClassesToApply" is an array of strings that is stored at location formElement.beEnhanced.beFormidable.invalidClassesToApply. It lists validation errors.
As mentioned in the beginning, the examples so far do not result in automatically calling checkValidity (except, by default as soon as the behavior is attached), so nothing will actually happen unless some other script is invoking checkValidity.
We can specify when to automatically call checkValidity.
Simplest:
<form be-formidable='{
"invalidIf":[
{
"noneOf": ["url", "file"],
"message": "Select a url or a file"
}
],
"checkValidityOn": "input"
}'>
...
</form>
If multiple events / optional settings are required:
<form be-formidable='{
"invalidIf":[
{
"noneOf": ["url", "file"],
"message": "Select a url or a file"
}
],
"checkValidityOn": [
"input",
{
"type": "change",
"options": {
"capture": true
}
}
]
}'>
...
</form>
Unfortunately, the platform does not yet support specifying a custom validation function for a form element.
This means that the :valid and :invalid pseudo-classes are not adjusted as needed.
The be-formidable enhancement does set "valid" or "invalid" classes during the checkValidity() calls.
Suggested CSS:
<style>
form:invalid, form.be-formidable.invalid {
border: 5px solid red;
}
form:valid, form.be-formidable.valid {
border: 5px solid green;
}
</style>
Any web server that serves static files will do but...
- Install git.
- Fork/clone this repo.
- Install node.
- Open command window to folder where you cloned this repo.
-
npm install
-
npm run serve
- Open http://localhost:8000/demo in a modern browser.
import 'be-formidable/be-formidable.js';
<script type=module crossorigin=anonymous>
import 'https://esm.run/be-formidable';
</script>