From aedcc22958c12365366bf6696ee2b043171596e4 Mon Sep 17 00:00:00 2001 From: Francesco Boscarino Date: Tue, 26 May 2020 11:10:02 +0200 Subject: [PATCH 1/5] Submit button to handle valid state --- lib/components/Submit.svelte | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lib/components/Submit.svelte diff --git a/lib/components/Submit.svelte b/lib/components/Submit.svelte new file mode 100644 index 0000000..6fcbe61 --- /dev/null +++ b/lib/components/Submit.svelte @@ -0,0 +1,16 @@ + + + From 96a44fb3a88a192fac0c648e629961f75cddb637 Mon Sep 17 00:00:00 2001 From: Francesco Boscarino Date: Tue, 26 May 2020 11:15:22 +0200 Subject: [PATCH 2/5] Export Submit component Removed touched check from isValid --- lib/components/Submit.svelte | 7 +- lib/createForm.js | 313 ++++++++++++++++++----------------- lib/index.js | 17 +- 3 files changed, 171 insertions(+), 166 deletions(-) diff --git a/lib/components/Submit.svelte b/lib/components/Submit.svelte index 6fcbe61..d8feab4 100644 --- a/lib/components/Submit.svelte +++ b/lib/components/Submit.svelte @@ -2,12 +2,7 @@ import { getContext } from "svelte"; import { key } from "./key"; -const { state, updateTouched } = getContext(key); - -console.log($state) -for(let field in $state.touched) { - console.log(field) -} +const { state } = getContext(key); diff --git a/lib/createForm.js b/lib/createForm.js index 0b49406..fbe1fc6 100644 --- a/lib/createForm.js +++ b/lib/createForm.js @@ -5,168 +5,171 @@ const NO_ERROR = ""; const IS_TOUCHED = true; export const createForm = config => { - const initialValues = config.initialValues || {}; - - if (Object.keys(initialValues).length < 1) { - const provided = JSON.stringify(initialValues); - console.warn( - `createForm requires initialValues to be a non empty object or array, provided ${provided}` - ); - return; - } - - const validationSchema = config.validationSchema; - const validateFn = config.validate; - const onSubmit = config.onSubmit; - - const initial = { - values: () => util.cloneDeep(initialValues), - errors: () => util.assignDeep(initialValues, NO_ERROR), - touched: () => util.assignDeep(initialValues, !IS_TOUCHED) - }; - - const form = writable(initial.values()); - const errors = writable(initial.errors()); - const touched = writable(initial.touched()); - - const isSubmitting = writable(false); - const isValidating = writable(false); - - const isValid = derived([errors, touched], ([$errors, $touched]) => { - const allTouched = util - .getValues($touched) - .every(field => field === IS_TOUCHED); - const noErrors = util.getValues($errors).every(field => field === NO_ERROR); - return allTouched && noErrors; - }); - - function isCheckbox(el) { - return el.getAttribute && el.getAttribute('type') === 'checkbox'; - } - - function handleChange(event) { - const el = event.target; - const field = el.name; - const value = isCheckbox(el) ? el.checked : el.value; - - updateTouched(field, true); - - if (validationSchema) { - isValidating.set(true); - return util - .reach(validationSchema, field) - .validate(value) - .then(() => util.update(errors, field, "")) - .catch(err => util.update(errors, field, err.message)) - .finally(() => { - updateField(field, value); - isValidating.set(false); - }); + const initialValues = config.initialValues || {}; + + if (Object.keys(initialValues).length < 1) { + const provided = JSON.stringify(initialValues); + console.warn( + `createForm requires initialValues to be a non empty object or array, provided ${provided}` + ); + return; } - if (validateFn) { - isValidating.set(true); - return Promise.resolve() - .then(() => validateFn({ [field]: value })) - .then(errs => util.update(errors, field, errs[field])) - .finally(() => { - updateField(field, value); - isValidating.set(false); - }) - } + const validationSchema = config.validationSchema; + const validateFn = config.validate; + const onSubmit = config.onSubmit; + + const initial = { + values: () => util.cloneDeep(initialValues), + errors: () => util.assignDeep(initialValues, NO_ERROR), + touched: () => util.assignDeep(initialValues, !IS_TOUCHED) + }; + + const form = writable(initial.values()); + const errors = writable(initial.errors()); + const touched = writable(initial.touched()); + + const isSubmitting = writable(false); + const isValidating = writable(false); + + const isValid = derived([errors, touched], ([$errors, $touched]) => { + /* + const allTouched = util + .getValues($touched) + .every(field => field === IS_TOUCHED); + */ + const noErrors = util.getValues($errors).every(field => field === NO_ERROR); + return /* allTouched && */ noErrors; + }); - updateField(field, value); - } + function isCheckbox(el) { + return el.getAttribute && el.getAttribute('type') === 'checkbox'; + } - function handleSubmit(ev) { - if (ev && ev.preventDefault) { - ev.preventDefault(); + function handleChange(event) { + const el = event.target; + const field = el.name; + const value = isCheckbox(el) ? el.checked : el.value; + + updateTouched(field, true); + + if (validationSchema) { + isValidating.set(true); + return util + .reach(validationSchema, field) + .validate(value) + .then(() => util.update(errors, field, "")) + .catch(err => util.update(errors, field, err.message)) + .finally(() => { + updateField(field, value); + isValidating.set(false); + }); + } + + if (validateFn) { + isValidating.set(true); + return Promise.resolve() + .then(() => validateFn({ + [field]: value })) + .then(errs => util.update(errors, field, errs[field])) + .finally(() => { + updateField(field, value); + isValidating.set(false); + }) + } + + updateField(field, value); } - isSubmitting.set(true); + function handleSubmit(ev) { + if (ev && ev.preventDefault) { + ev.preventDefault(); + } - return util.subscribeOnce(form).then(values => { - if (typeof validateFn === "function") { - isValidating.set(true); + isSubmitting.set(true); - return Promise.resolve() - .then(() => validateFn(values)) - .then(err => - util.isEmpty(err) ? clearErrorsAndSubmit(values) : errors.set(err) - ) - .finally(() => isValidating.set(false)); - } - - if (validationSchema) { - isValidating.set(true); - - return validationSchema - .validate(values, { abortEarly: false }) - .then(() => clearErrorsAndSubmit(values)) - .catch(yupErrs => { - if (yupErrs && yupErrs.inner) { - yupErrs.inner.forEach(error => - util.update(errors, error.path, error.message) - ); + return util.subscribeOnce(form).then(values => { + if (typeof validateFn === "function") { + isValidating.set(true); + + return Promise.resolve() + .then(() => validateFn(values)) + .then(err => + util.isEmpty(err) ? clearErrorsAndSubmit(values) : errors.set(err) + ) + .finally(() => isValidating.set(false)); } - isSubmitting.set(false); - }) - .finally(() => isValidating.set(false)); - } - clearErrorsAndSubmit(values); - }); - } - - function handleReset() { - form.set(initial.values()); - errors.set(initial.errors()); - touched.set(initial.touched()); - } - - function clearErrorsAndSubmit(values) { - return Promise.resolve() - .then(() => errors.set(util.assignDeep(values, ""))) - .then(() => onSubmit(values, form, errors)) - .finally(() => isSubmitting.set(false)); - } - - /** - * Handler to imperatively update the value of a form field - */ - function updateField(field, value) { - util.update(form, field, value); - } - - /** - * Handler to imperatively update the touched value of a form field - */ - function updateTouched(field, value) { - util.update(touched, field, value); - } - - return { - form, - errors, - touched, - isValid, - isSubmitting, - isValidating, - handleChange, - handleSubmit, - handleReset, - updateField, - updateTouched, - state: derived( - [form, errors, touched, isValid, isValidating, isSubmitting], - ([$form, $errors, $touched, $isValid, $isValidating, $isSubmitting]) => ({ - form: $form, - errors: $errors, - touched: $touched, - isValid: $isValid, - isSubmitting: $isSubmitting, - isValidating: $isValidating - }) - ) - }; -}; + if (validationSchema) { + isValidating.set(true); + + return validationSchema + .validate(values, { abortEarly: false }) + .then(() => clearErrorsAndSubmit(values)) + .catch(yupErrs => { + if (yupErrs && yupErrs.inner) { + yupErrs.inner.forEach(error => + util.update(errors, error.path, error.message) + ); + } + isSubmitting.set(false); + }) + .finally(() => isValidating.set(false)); + } + + clearErrorsAndSubmit(values); + }); + } + + function handleReset() { + form.set(initial.values()); + errors.set(initial.errors()); + touched.set(initial.touched()); + } + + function clearErrorsAndSubmit(values) { + return Promise.resolve() + .then(() => errors.set(util.assignDeep(values, ""))) + .then(() => onSubmit(values, form, errors)) + .finally(() => isSubmitting.set(false)); + } + + /** + * Handler to imperatively update the value of a form field + */ + function updateField(field, value) { + util.update(form, field, value); + } + + /** + * Handler to imperatively update the touched value of a form field + */ + function updateTouched(field, value) { + util.update(touched, field, value); + } + + return { + form, + errors, + touched, + isValid, + isSubmitting, + isValidating, + handleChange, + handleSubmit, + handleReset, + updateField, + updateTouched, + state: derived( + [form, errors, touched, isValid, isValidating, isSubmitting], + ([$form, $errors, $touched, $isValid, $isValidating, $isSubmitting]) => ({ + form: $form, + errors: $errors, + touched: $touched, + isValid: $isValid, + isSubmitting: $isSubmitting, + isValidating: $isValidating + }) + ) + }; +}; \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 57d9b7a..fcc3e36 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,12 @@ -export { createForm } from "./createForm"; -export { default as Form } from "./components/Form.svelte"; -export { default as Field } from "./components/Field.svelte"; -export { default as Select } from "./components/Select.svelte"; -export { default as ErrorMessage } from "./components/ErrorMessage.svelte"; +export { createForm } +from "./createForm"; +export { default as Form } +from "./components/Form.svelte"; +export { default as Field } +from "./components/Field.svelte"; +export { default as Select } +from "./components/Select.svelte"; +export { default as ErrorMessage } +from "./components/ErrorMessage.svelte"; +export { default as Submit } +from "./components/Submit.svelte"; \ No newline at end of file From 5a35b9c74485e05c3551c27eb51c3d6f91a57144 Mon Sep 17 00:00:00 2001 From: Francesco Boscarino Date: Tue, 26 May 2020 18:35:06 +0200 Subject: [PATCH 3/5] Added checkbox to Field component --- lib/components/Field.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/components/Field.svelte b/lib/components/Field.svelte index dd99864..2289de5 100644 --- a/lib/components/Field.svelte +++ b/lib/components/Field.svelte @@ -12,6 +12,7 @@ {name} type={type} value={$form[name]} + checked={$form[name]} on:change={handleChange} on:blur={handleChange} {...$$props} /> From 37c9898ed44074649946b15d4d7651a03e71a3ea Mon Sep 17 00:00:00 2001 From: Francesco Boscarino Date: Wed, 27 May 2020 15:37:39 +0200 Subject: [PATCH 4/5] Validate single field with all context --- lib/createForm.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/createForm.js b/lib/createForm.js index fbe1fc6..51fe186 100644 --- a/lib/createForm.js +++ b/lib/createForm.js @@ -55,9 +55,8 @@ export const createForm = config => { if (validationSchema) { isValidating.set(true); - return util - .reach(validationSchema, field) - .validate(value) + return validationSchema + .validateAt(field, context) .then(() => util.update(errors, field, "")) .catch(err => util.update(errors, field, err.message)) .finally(() => { @@ -70,7 +69,8 @@ export const createForm = config => { isValidating.set(true); return Promise.resolve() .then(() => validateFn({ - [field]: value })) + [field]: value + })) .then(errs => util.update(errors, field, errs[field])) .finally(() => { updateField(field, value); From d016e68b689831d5fdb9822bd315594dcdc8a69a Mon Sep 17 00:00:00 2001 From: Francesco Boscarino Date: Wed, 27 May 2020 15:41:53 +0200 Subject: [PATCH 5/5] Missing store subcribe --- lib/createForm.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/createForm.js b/lib/createForm.js index 51fe186..7a64cb2 100644 --- a/lib/createForm.js +++ b/lib/createForm.js @@ -29,6 +29,9 @@ export const createForm = config => { const errors = writable(initial.errors()); const touched = writable(initial.touched()); + let context; + form.subscribe(val => context = val); + const isSubmitting = writable(false); const isValidating = writable(false);