Last active
May 2, 2022 19:32
-
-
Save wittyprogramming/730f71e0507bcf2328aafa4137876b06 to your computer and use it in GitHub Desktop.
Form Validation using Alpine.js framework applying a Vue composition-like architecture.
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 { | |
isEmail, | |
isMaxLength, | |
isMinLength, | |
isRequired, | |
} from "./validators.mjs"; | |
export function formValidator() { | |
let submitBackend; | |
return { | |
name: null, | |
nameDirty: false, | |
email: null, | |
emailDirty: false, | |
comments: null, | |
commentsDirty: false, | |
isNameValid(maxLength) { | |
return ( | |
this.nameDirty && | |
isRequired(this.name) && | |
(maxLength ? isMaxLength(this.name, maxLength) : true) | |
); | |
}, | |
isEmailValid() { | |
return this.emailDirty && isEmail(this.email); | |
}, | |
isCommentsValid(minLength) { | |
return ( | |
this.commentsDirty && | |
isRequired(this.comments) && | |
(minLength ? isMinLength(this.comments, minLength) : true) | |
); | |
}, | |
isFormValid() { | |
return ( | |
this.isNameValid() && this.isEmailValid() && this.isCommentsValid() | |
); | |
}, | |
submitForm(formElement) { | |
this.nameDirty = true; | |
this.emailDirty = true; | |
this.commentsDirty = true; | |
if (!this.isFormValid()) return; | |
submitBackend(formElement); | |
}, | |
formValidator_init(backend) { | |
submitBackend = backend; | |
}, | |
}; | |
} |
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<script type="module" defer> | |
import { formValidator } from "./form-validator.mjs" | |
import { netlifySubmission } from "./netlify.mjs" | |
window.contactForm = function() { | |
return { | |
...netlifySubmission(), | |
...formValidator(), | |
init() { | |
this.formValidator_init(this.submitToNetlify); | |
} | |
} | |
} | |
</script> | |
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script> | |
<style> | |
[x-cloak] { | |
display: none; | |
} | |
</style> | |
<title>Sample Contact Form for Netlify using Alpine.js component-based composition approach</title> | |
</head> | |
<body> | |
<h1>Sample Contact Form for Netlify using Alpine.js</h1> | |
<form | |
hidden | |
name="contact" | |
method="POST" | |
data-netlify="true" | |
netlify-honeypot="bot-field" | |
data-netlify-recaptcha="true" | |
> | |
<label><input type="text" name="name" /></label> | |
<label> <input type="email" name="email" /></label> | |
<label><textarea name="message"></textarea></label> | |
<div data-netlify-recaptcha="true"></div> | |
</form> | |
<form | |
x-data="contactForm()" | |
x-on:submit.prevent="submitForm($refs.contactForm);" | |
x-ref="contactForm" | |
x-init="init()" | |
id="contact" | |
> | |
<p hidden> | |
<label>ignore: <input name="bot-field" /></label> | |
</p> | |
<input type="hidden" name="form-name" value="contact" /> | |
<p> | |
<label | |
>Full Name: <input x-model="name" x-on:blur="nameDirty = true" type="text" name="name" | |
/></label> | |
</p> | |
<p x-show.transition="!isNameValid() && nameDirty" style="color: red" x-cloak> | |
Please fill out your full name. | |
</p> | |
<p> | |
<label | |
>Email: <input x-model="email" x-on:blur="emailDirty = true" type="email" name="email" | |
/></label> | |
</p> | |
<p x-show.transition="!isEmailValid() && emailDirty" style="color: red" x-cloak> | |
Please provide a valid email. | |
</p> | |
<p> | |
<label | |
>Message: | |
<textarea x-model="comments" x-on:blur="commentsDirty = true" name="message"></textarea> | |
</label> | |
</p> | |
<p x-show.transition="!isCommentsValid(5) && commentsDirty" style="color: red" x-cloak> | |
Please fill out your Message with at least 5 characters. | |
</p> | |
<div data-netlify-recaptcha="true"></div> | |
<p> | |
<button type="submit">Send</button> | |
</p> | |
</form> | |
</body> | |
</html> |
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
export function netlifySubmission() { | |
return { | |
submitToNetlify(formElement) { | |
let body = new URLSearchParams(new FormData(formElement)).toString(); | |
return fetch("/", { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/x-www-form-urlencoded", | |
}, | |
body: body, | |
}) | |
.then((response) => { | |
if (response.ok) { | |
formElement.reset(); | |
alert("Thank you for your message!"); | |
} else { | |
throw new Error(`Something went wrong: ${response.statusText}`); | |
} | |
}) | |
.catch((error) => console.error(error)); | |
}, | |
}; | |
} |
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
export function isEmail(value) { | |
return new RegExp("^\\S+@\\S+[\\.][0-9a-z]+$").test( | |
String(value).toLowerCase() | |
); | |
} | |
export function isRequired(value) { | |
return value !== null && value !== undefined && value.length > 0; | |
} | |
export function isMinLength(value, length) { | |
return String(value).length >= length; | |
} | |
export function isMaxLength(value, length) { | |
return String(value).length <= length; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment