@author Michael Rhodes
@license MIT
Made in Barbados 🇧🇧 Copyright © 2020-2021 Michael Rhodes
MolaMola provides a framework for building forms with validation, captcha, csrf and other plugin capabilities.
<form id="test-form" data-sargasso-class="MolaMola" action="/form-post" method="POST" data-submitter=".submitter" data-status=".status" data-recaptcha="xxx" data-helpers="HelperOne,HelperTwo">
....
<button class="submitter">submit</button>
<p class="status"></p>
</form>
Attributes:
id
: the id of the form (required)action
: endpoint to transmit data tomethod
: method (POST,GET,PATCH etc)data-helpers
: list of MolaMola Helper classes for handling errors and response payload etc.data-submitter
: css selector of the form submit button. button will be enabled only when input is valid.data-status
: css selector of a container where errors are displayeddata-recaptcha
: public reCaptchaV3 API key.
If using reCaptchaV3 The recaptcha script must be included with an API id on the page. It will be called on form submit and the token will be added to the payload (g-recaptcha-response) for backend validation and scoring.
<head>
<script src="https://www.google.com/recaptcha/api.js?render=xxx"></script>
</head>
<div class="input-group">
<input type="text" name="email" placeholder="Email address" data-validate='{"isEmail":true,"notEmpty":true}' data-payload>
<span class="validation-help"></span>
</div>
Input Attributes:
name
: payload property (required)data-validate
: JSON string detailing applicable Field validatorsdata-validate-message
: message to display on validation error (default messages are somewhat cryptic)data-payload
: set if the field should be included in form payload
The built in validation helper marks input errors and displays input error messages
Field validation is implemented by Validator using Sequelize extensions.
Prerequisites for validation behavior:
- All input elements must be wrapped in an
.input-group
container - All validated inputs must have an
.validation-help
container inside the.input-group
for displaying errors
CSS rules to reveal validation messages on input error
.validation-help { opacity:0; }
.touched .error .validation-help { opacity: 1}
Example validators See Validator for details:
data-validate='{"isEmail":true,"notEmpty":true}'
data-validate='{"isInt":{"min":1,"max":2}}' data-validate-message='{"isInt":"integer between %s and %s"}'
data-validate='{"isLength":{"min":0,"max":10}}'
Note: the format of the attributes must be valid JSON (double quotes required)
Grouping payloads for multiple and single select, checkboxes and radio buttons
<div class="input-group">
<input type="text" name="checkbox-group" data-group='[type="checkbox"]' data-validate='{"notEmpty":true}' multiple data-payload>
<input type="checkbox" value="1" checked> Check 1
<input type="checkbox" value="2"> Check 2
<input type="checkbox" value="3" checked> Check 3
<span class="validation-help"></span>
</div>
<div class="input-group">
<input type="text" name="radio-group" data-group='[type="radio"]' data-payload>
<input type="radio" name="radio" value="1" checked> radio 1
<input type="radio" name="radio" value="2"> radio 2
<input type="radio" name="radio" value="3"> radio 3
<span class="validation-help"></span>
</div>
<div class="input-group">
<select name="select-single" data-validate='{"notEmpty":true}' data-payload>
<option value="">---</option>
<option value="1">option 1</option>
<option value="2" selected>option 2</option>
<option value="3">option 2</option>
</select>
<span class="validation-help"></span>
</div>
<div class="input-group">
<select name="select-multiple" data-validate='{"notEmpty":true}' multiple data-payload>
<option value="">---</option>
<option value="1" selected>option 1</option>
<option value="2" selected>option 2</option>
<option value="3">option 2</option>
</select>
<span class="validation-help"></span>
</div>
The resulting payload groups multiple and single selects in a consistent manner
{
"checkbox-group" : [2,3],
"radio-group": 1,
"select-single": 2,
"select-multiple": [1,2]
}
Make an API call on change to validate uniqueness or existence for a field value
TODO: need example
This example hooks up a helper to a form
class ExampleHandler extends MolaMolaModule.MolaMolaHelper {
// A chance to modify the payload or implement a captcha or something before submit.
preFlight() {
}
// use this method to handle 200 (ok) and 422 (unprocessable entity) responses
// this example expects a JSON response. The specification of the payload is up to you.
success(data) {
alert('submitted')
}
// use this method to handle all other http responses
error(err) {
alert('error ' + err.message)
}
}
MolaMolaModule.molaMolaUtils.registerHelperClass('ExampleHandler', ExampleHandler)
<form id="test-form" data-sargasso-class="MolaMola" data-helpers="ExampleHandler" action="/form-post" method="POST" data-submitter=".submitter" data-status=".status">
Backend API prerequisites for the endpoint:
-
200 (ok) & 422 (unprocessable entity) are expected to return json. Use 422 for server side validation errors, the response payload is up to implementor and should be handled with a helper
success
method. -
Other http errors such as 401 (unauthorized) are handed to the helper
error
method
You will at least need to receive the payload of the response to take action after the form is submitted and probably show a confirmation page in success or something like that.
Subclass MolaMolaHelper
and override the success
and error
methods to see the response payload and errors. This implementation is up to you. In our example response payload has some sugar to take some actions based on the response.
npm install @pelagiccreatures/sargasso --save-dev
npm install @pelagiccreatures/molamola --save-dev
You can use the .iife.js bundles in the /dist directory of the @PelagicCreatures modules by copying them to a public directory on your server and referencing them in script tags in your html.
node_modules/@pelagiccreatures/sargasso/dist/sargasso.iife.js
node_modules/@pelagiccreatures/molamola/dist/molamola.iife.js
-or-
You can also bundle sargasso modules with your own es6 code using rollup.
npm install npx -g
npm install rollup --save-dev
npm install @rollup/plugin-json --save-dev
npm install @rollup/plugin-commonjs --save-dev
npm install @rollup/plugin-node-resolve --save-dev
npm install rollup-plugin-terser --save-dev
app.js
import { Sargasso, utils, loadPageHandler } from '@pelagiccreatures/sargasso'
import { MolaMola } from '@pelagiccreatures/molamola'
const boot = () => {
utils.bootSargasso({})
}
export {
boot
}
html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="public/dist/js/userapp.iife.js" defer></script>
<script defer>
window.onload= () => {
App.boot()
}
</script>
</body>
</html>
Set input and output ass needed.
rollup.config.js
import commonjs from '@rollup/plugin-commonjs'
import nodeResolve from '@rollup/plugin-node-resolve'
import json from '@rollup/plugin-json'
import {
terser
}
from 'rollup-plugin-terser'
export default {
input: './app.js', // <<< location of your es6 code
output: {
format: 'iife',
file: 'public/dist/js/userapp.iife.js', // <<< where to save the browser bundle
name: 'App', // <<< global variable where app.js exports are exposed
sourcemap: true,
compact: true
},
plugins: [
json(),
commonjs({}),
nodeResolve({
preferBuiltins: false,
dedupe: (dep) => {
return dep.match(/^(@pelagiccreatures|lodash|js-cookie)/)
}
}),
terser({
output: {
comments: false
},
keep_classnames: true,
keep_fnames: true
})
]
}
Make the bundle
npx rollup --no-treeshake --no-freeze -c rollup.config.js