A Pen by Hugh Haworth on CodePen.
Created
December 4, 2022 14:03
-
-
Save imanifaiz/f0854c6903a010d1e09d8bc5a721b262 to your computer and use it in GitHub Desktop.
Form validation with Alpine.JS and Iodine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <form action="" x-data="form" @focusout="change" @input="change" @submit="submit"> | |
| <h1>Register</h1> | |
| <label for="username">Username</label> | |
| <input name="username" id="username" type="text" x-bind:class="{'invalid':username.errorMessage}" data-rules='["required"]' data-server-errors='[]'> | |
| <p class="error-message" x-show="username.errorMessage" x-text="username.errorMessage" x-transition:enter></p> | |
| <label for="email">Email</label> | |
| <input name="email" type="email" id="email" x-bind:class="{'invalid':email.errorMessage}" data-rules='["required","email"]' data-server-errors='[]'> | |
| <p class="error-message" x-show="email.errorMessage" x-text="email.errorMessage" x-transition:enter></p> | |
| <label for="password">Password</label> | |
| <input name="password" type="password" id="password" x-bind:class="{'invalid':password.errorMessage}" data-rules='["required","minLength:8"]' data-server-errors='[]'> | |
| <p class="error-message" x-show="password.errorMessage" x-text="password.errorMessage" x-transition:enter></p> | |
| <label for="passwordConf">Confirm Password</label> | |
| <input name="passwordConf" type="password" id="passwordConf" x-bind:class="{'invalid': passwordConf.errorMessage}" data-rules='["required","minLength:8","matchingPassword"]' data-server-errors='[]'> | |
| <p class="error-message" x-show="passwordConf.errorMessage" x-text="passwordConf.errorMessage" x-transition:enter></p> | |
| <input type="submit"> | |
| </form> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Alpine from "https://cdn.skypack.dev/alpinejs"; | |
| import kingshottIodine from "https://cdn.skypack.dev/@kingshott/iodine"; | |
| Alpine.data("form", form); | |
| Alpine.start(); | |
| function form() { | |
| return { | |
| inputElements: [], | |
| init() { | |
| //Set up custom Iodine rules | |
| Iodine.rule( | |
| "matchingPassword", | |
| (value) => value === document.getElementById("password").value | |
| ); | |
| Iodine.setErrorMessage( | |
| "matchingPassword", | |
| "Password confirmation needs to match password" | |
| ); | |
| //Store an array of all the input elements with 'data-rules' attributes | |
| this.inputElements = [...this.$el.querySelectorAll("input[data-rules]")]; | |
| this.initDomData(); | |
| this.updateErrorMessages(); | |
| }, | |
| initDomData: function () { | |
| //Create an object attached to the component state for each input element to store its state | |
| this.inputElements.map((ele) => { | |
| this[ele.name] = { | |
| serverErrors: JSON.parse(ele.dataset.serverErrors), | |
| blurred: false | |
| }; | |
| }); | |
| }, | |
| updateErrorMessages: function () { | |
| //map throught the input elements and set the 'errorMessage' | |
| this.inputElements.map((ele) => { | |
| this[ele.name].errorMessage = this.getErrorMessage(ele); | |
| }); | |
| }, | |
| getErrorMessage: function (ele) { | |
| //Return any server errors if they're present | |
| if (this[ele.name].serverErrors.length > 0) { | |
| return input.serverErrors[0]; | |
| } | |
| //Check using iodine and return the error message only if the element has not been blurred | |
| const error = Iodine.assert(ele.value, JSON.parse(ele.dataset.rules)); | |
| if (!error.valid && this[ele.name].blurred) { | |
| return error.error; | |
| } | |
| //return empty string if there are no errors | |
| return ""; | |
| }, | |
| submit: function (event) { | |
| const invalidElements = this.inputElements.filter((input) => { | |
| return ( | |
| Iodine.assert(input.value, JSON.parse(input.dataset.rules)) !== true | |
| ); | |
| }); | |
| if (invalidElements.length > 0) { | |
| event.preventDefault(); | |
| document.getElementById(invalidElements[0].id).scrollIntoView(); | |
| //We set all the inputs as blurred if the form has been submitted | |
| this.inputElements.map((input) => { | |
| this[input.name].blurred = true; | |
| }); | |
| //And update the error messages. | |
| this.updateErrorMessages(); | |
| } | |
| }, | |
| change: function (event) { | |
| //Ignore all events that aren't coming from the inputs we're watching | |
| if (!this[event.target.name]) { | |
| return false; | |
| } | |
| if (event.type === "input") { | |
| this[event.target.name].serverErrors = []; | |
| } | |
| if (event.type === "focusout") { | |
| this[event.target.name].blurred = true; | |
| } | |
| //Whether blurred or on input, we update the error messages | |
| this.updateErrorMessages(); | |
| } | |
| }; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| * { | |
| font-family: "Inter", sans-serif; | |
| } | |
| form { | |
| width: 40%; | |
| min-width: 450px; | |
| margin: auto; | |
| } | |
| label { | |
| font-size: 1.5em; | |
| } | |
| input { | |
| width: 100%; | |
| display: block; | |
| font-size: 2em; | |
| border: solid 4px; | |
| border-color: hsl(210, 100%, 30%); | |
| margin-bottom: 1.5em; | |
| } | |
| input[type="submit"] { | |
| width: fit-content; | |
| font-size: 1.5em; | |
| } | |
| input[type="submit"]:focus { | |
| background-color: hsl(210, 100%, 80%); | |
| } | |
| input[type="submit"]:active { | |
| background-color: hsl(200, 100%, 80%); | |
| } | |
| .invalid { | |
| border-color: darkred; | |
| background-color: hsl(0, 30%, 95%); | |
| margin-bottom: 0em; | |
| } | |
| .error-message { | |
| margin-bottom: 1em; | |
| color: hsl(0deg, 100%, 15%); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@500&display=swap" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment