Validation with Iodine
This section will present an example of how to implement client-side validation using the Iodine library. We will process a simple form with two fields, name and E-mail.
DANGER
Client-side validation is insecure and should only be implemented for the convenience of the user.
Adding library
For simplicity of the example, let's connect it via CDN.
<script src="https://cdn.jsdelivr.net/npm/@caneara/iodine@8/dist/iodine.min.umd.js" defer></script>
Form layout
Nothing unusual, except for the novalidate
attribute added to the form element. It is needed to disable the browser's built-in validation.
<form action="[[~[[*id]]]]" method="post" novalidate>
<label> Name
<input type="text" name="name" value="[[+fi.name]]" />
<span data-error="name">[[+fi.error.name]]</span>
</label>
<label> E-mail
<input type="email" name="email" value="[[+fi.email]]" />
<span data-error="email">[[+fi.error.email]]</span>
</label>
<button>Submit</button>
</form>
Handler
Now we have to add a handler to the fetchit:before
event, where the validation will take place. We will explain it step by step.
Adding a handler to the
fetchit:before
event.jsdocument.addEventListener('fetchit:before', (e) => { });
Get references to instances of
FormData
andFetchIt
classes.jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; });
The Iodine library can validate a data group by passing it a prepared object with the field name as the key and the value as the value. To do this, we just need to turn an instance of FormData into a simple object.
jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; const fields = Object.fromEntries(formData.entries()); });
Let's prepare field validation rules.
jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; const fields = Object.fromEntries(formData.entries()); const rules = { name: ['required', 'minLength:5'], email: ['required', 'email'], }; });
Let's perform the validation by writing the result to a variable.
jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; const fields = Object.fromEntries(formData.entries()); const rules = { name: ['required', 'minLength:5'], email: ['required', 'email'], }; const validation = Iodine.assert(fields, rules); });
Let's write a condition that if the validation is successful, we terminate our handler with
return
. And then call thepreventDefault()
method of our event to stop sending the form.jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; const fields = Object.fromEntries(formData.entries()); const rules = { name: ['required', 'minLength:5'], email: ['required', 'email'], }; const validation = Iodine.assert(fields, rules); if (validation.valid) { return; } e.preventDefault(); });
Next, we're going through our fields.
jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; const fields = Object.fromEntries(formData.entries()); const rules = { name: ['required', 'minLength:5'], email: ['required', 'email'], }; const validation = Iodine.assert(fields, rules); if (validation.valid) { return; } e.preventDefault(); for (const [ name, field ] of Object.entries(validation.fields)) { } });
If the field is valid (we are talking about the validation state of each field, not all of them), then we clear its errors using the
clearError()
method, otherwise we add an error to the field using thesetError()
method.jsdocument.addEventListener('fetchit:before', (e) => { const { formData, fetchit } = e.detail; const fields = Object.fromEntries(formData.entries()); const rules = { name: ['required', 'minLength:5'], email: ['required', 'email'], }; const validation = Iodine.assert(fields, rules); if (validation.valid) { return; } e.preventDefault(); for (const [ name, field ] of Object.entries(validation.fields)) { if (field.valid) { fetchit.clearError(name); continue; } fetchit.setError(name, field.error); } });
Done! This is how we can add validation using the Iodine library, but remember, it is not secure on the client side. So when calling the snippet, you should use the validation tools of FormIt or if you use your own snippet, you should do it there as well.
An example of a snippet call with FormIt validation:
[[!FetchIt?
&form=`myForm.tpl`,
&validate=`name:required:minLength=^5^,email:required:email`
]]
{'!FetchIt' | snippet : [
'form' => 'myForm.tpl',
'validate' => 'name:required:minLength=^5^,email:required:email',
]}
A list of all FormIt validators can be found on the documentation site of the component.