formul8
v0.5.0
Published
Automatic form handling
Readme
NAME
formul8 — Automatic form handling
SYNOPSIS
import { formul8 } from "formul8"
const [form_data, change_event] = formul8("my_form_id")
do_stuff(form_data)
document.addEventListener(change_event, () => do_stuff(form_data))DESCRIPTION
Takes in a <form/> (or any HTML element) that contains <input/>,
<select/>, and <textarea/> elements, and returns an object that represents
the "state" of the form. Each of the input-like elements within the form will
have an entry in the state object whose key is the input name if present,
else the id if present, else a value auto-generated by formul8.
When any of the form elements change, the state object will be updated and a
custom event will be fired on the document. The name of this event is the
second thing returned by formul8, and the event object holds the state
object in the detail field.
When the values of state object change, the form is updated to change with them and the same custom event is fired.
Any <fieldset/> elements in the form create sub-objects, where the key of
the sub-object is the fieldset name is present, else the id if present,
else the text of a child <legend/> if present, else a value auto generated
by formul8.
OPTIONS
Additional options can be passed to formul8 through the optional
parameter options, a JSON object.
DEBOUNCE
If options.debounce is a number, it overrides the default debounce period on
the form (0 milliseconds).
EVENTS
If options.events is a list of strings, it becomes the list of events that
the form listens for to detect changes.
DIRECTION
If options.direction is a update_dir enum value, it will define which ways
the form updates. The directions are:
update_dir.from_form = 1 // Changing the form elements changes the object.
update_dir.to_form = 2 // Changing the object changes the form elements.The default value is update_dir.from_form | update_dir.to_form, A.K.A.
bidirectional.
AUTO_NOTIFY
If options.auto_notify is true and direction includes update_dir.to_form,
then changing the state object automatically fires the custom change event
in addition to updating the form. If you want to control this manually, set
options.auto_notify to false and use notify(change_event, form_data) to
manually fire the custom change event.
CUSTOM_INPUTS
Custom input elements can be defined by seting options.custom_inputs to
a dictionary of CSS selectors and getter/setter pairs:
{
"div.custom_input1": {
get: (element: HTMLElement): any => some_getter(element),
set: (element: HTMLElement, value: any) => some_setter(element, value),
},
}The get function is called when populating the state object from the
form. The passed element is the one that matches the selector, and it
should return the value to be stored in the state object.
The set function is called when populating the form from the state
object. The passed element is the one that matches the selector, and the
value is that present within the state object. It should return nothing,
but as a side effect it should update the form element to hold the given
value.
[!NOTE]
Keep in mind that custom elements still need to alert formul8 when they change. If the altering event already bubbles up to the form, and formul8 is configured to recognize that event, no changes need to be made. Otherwise, the developer will need to dispatch an event that bubbles up to the form.
For example, say formul8 is not configured to recognize
clickevents, but it does recognizechangeevents. For a custom element that updates when it is clicked:custom_input1.addEventListener("click", (ev) => { do_your_stuff(ev) // Send the parent form an alert that this input has changed. custom_input1.dispatchEvent(new Event("change", { bubbles: true })) })
EXAMPLE
<form id="user_input_form">
<input type="text" id="user_name" placeholder="Username..." />
<input type="password" id="user_pass" placeholder="Password..." />
<fieldset>
<legend>Address</legend>
<input type="text" id="line_1" placeholder="Line 1..." />
<input type="text" id="line_2" placeholder="Line 2..." />
<input type="text" id="city" placeholder="City..." />
<input type="text" id="province" placeholder="Province..." />
<input type="text" id="postal_code" placeholder="Postal code..." />
<select id="country">
<option>...</option>
<option>Martinaise</option>
<option>Revachol</option>
<option>Seol</option>
<option>Oranje</option>
</select>
</fieldset>
<input type="checkbox" id="terms_of_service" />
<label for="terms_of_service">I agree to the TOS</label>
<input type="checkbox" id="newsletter" />
<label for="newsletter">Sign me up for the newsletter</label>
</form>const [user_input, change_event] = formul8("user_input_form")
// user_input: {
// "address": {
// "line_1": string,
// "line_2": string,
// "city": string,
// "province": string,
// "postal_code": string,
// "country": string
// },
// "user_name": string,
// "user_pass": string,
// "terms_of_service": boolean,
// "newsletter": boolean
// }
do_stuff(user_input)
document.addEventListener(change_event, () => do_stuff(user_input))