Forms
control HTML forms easily, set form default values, reset, handleSumbit, reactive set and get form fields, all of that with support nested keys by dot notation fields names
html
<!DOCTYPE html>
<form onsubmit="handleSubmit(onSubmit, event)">
<input type="text" name="fname" />
<input type="text" name="user.name" />
<input type="text" name="user.fname" />
<input type="text" />
<button type="submit">submit</button>
</form>
<p></p>
<script>
// TODO: make stores for forms to get it's functions, or attach reset(), and others to component
// TODO: attach handlers to new elements added to form, and delete removed (only solutions available are use MutationObserver or export function to regenerate form.elements)
const proxyHandler = (form) => ({
set(target, key, value) {
form.elements[key].value = value
// convert dot notation to nested objects
// was target[key] = value
const keys = key.split('.')
let currentTarget = target
for (let i = 0; i < keys.length - 1; i++) {
const currentKey = keys[i];
if (!currentTarget[currentKey] || typeof currentTarget[currentKey] !== 'object') {
currentTarget[currentKey] = {};
}
currentTarget = currentTarget[currentKey];
}
currentTarget[keys[keys.length - 1]] = value;
return true
},
get(target, key) {
const keys = key.split('.');
let value = target;
for (const key of keys) {
if (value && typeof value === 'object') {
value = value[key];
} else {
return undefined;
}
}
return value;
}
})
const attach = (element) => {
element.oninput = (event) => {
controls[element.name] = event.target.value
};
};
function assignNestedProperties(target, obj, parent = null) {
for (const key in obj) {
const value = obj[key];
const prop = parent? `${parent}.${key}` : key
if (typeof value === 'object' && !Array.isArray(value)) {
assignNestedProperties(target, value, prop);
} else {
target[prop] = value;
}
}
}
function useForm({ defaultValues }, selector = 'form') {
const defaults = JSON.parse(JSON.stringify(defaultValues));
const form = document.querySelector(selector);
let controls = new Proxy(defaultValues ?? {}, proxyHandler(form));
// Attach event handlers to existing form elements
// for (element of Array.from(form.elements).filter(el => el.name))
// attach(element)
Array.from(form.elements).forEach((element) => {
if (element.name) {
attach(element);
element.value = controls[element.name]
}
});
return {
handleSubmit: (callback, event) => {
event.preventDefault();
callback(controls);
},
controls,
reset: (values) => {
if (!values) form.reset()
assignNestedProperties(controls, values);
}
};
}
const { handleSubmit, controls, reset } = useForm({
defaultValues: {
fname: 'ali',
user: { name: 'ali', fname: "dodo" }
}
})
function onSubmit(data) {
console.log(data)
console.log(data['user.fname'])
}
setTimeout(() => {
controls.fname = 'test'
controls['user.name'] = 'testo'
}, 3000)
setTimeout(() => {
reset({
fname: 'ali',
user: { name: 'ali', fname: "bobo" }
})
}, 5000)
</script>