svelte-forms-lib icon indicating copy to clipboard operation
svelte-forms-lib copied to clipboard

on:change and on:blur not working

Open kilianso opened this issue 4 years ago • 7 comments

  1. on:change and on:blur are not firing with custom validation.
  2. on:change is not firing with yup validation. on:blur works with yup as expected.

So error messages do not disappear because the change or blur is not firing.

kilianso avatar Jan 15 '20 22:01 kilianso

Hi @kilianso! Thanks for the issue.

  1. Regarding the on:change and on:blur not firing for custom validation — that's true.. Custom validation only supports full form validation at this point. Will update to support per field validation in a future update.

  2. on:change should work with Yup validation, could you give me an example snippet on where it does not work?

Also perhaps you can try to use the on:keyup binding:

<input on:keyup={handleChange} />

Let me know if that works for you

tjinauyeung avatar Jan 20 '20 10:01 tjinauyeung

Here's another example on how this works — https://svelte-forms-lib-sapper-docs.now.sh/observables

tjinauyeung avatar Jan 20 '20 10:01 tjinauyeung

Hi @tjinauyeung - thanks for your answer!

  1. So keyup is not a solution. The keyup event is not firing with custom validation anyway. Plus, even with Yup, the error message is shown as soon as the user uses tab to focus an input or starts typing, which is kinda bad UX. (e.g. when entering an email, an error is shown immediately) - Plus, there is no keyup event e.g. for a file input or a select menu (since most users are using the mouse for those field types).
  2. Here: https://svelte-forms-lib-sapper-docs.now.sh/yup - Steps to reproduce: Enter a wrong email so the error appears. Then edit the mail so it would be valid. on:change is not firing and removing the error as soon as there is a valid email. You have wait for blur or submit.

So expected behaviour:

  1. Don't show any errors in the first place. Not on focus, not on keyup, not on change.
  2. On blur and on submit, show errors if a field is not valid.
  3. As soon as the user edits the invalid field, check "live" with on change if the field is now valid and remove the errors.

That would be perfect :)

kilianso avatar Jan 20 '20 11:01 kilianso

Been wondering if actions would be a good angle to take here.

With the React informed library one can specify a validateOnBlur or validateOnChange property on a field, but what may be nice here would be to allow the user to specify an event to run validation with, and to remove it from the exported handleChange. This way handleChange is responsible exclusively for updating the value in the store, and actions are responsible for updating the error state. e.g.:

<script>
	const {handleChange, validateOn} = createForm({ /*...*/ })
</script>

<!-- specify exactly which events to run validation on -->
<input 
	use:validateOn={['change', 'blur']}
	on:change={handleChange}
/>

If no events are specified for the validateOn action, we could fall back to change. This may even allow one to specify a null event for validateOn so that no validation is run under certain conditions, e.g.:

<script>
	const {handleChange, validateOn, state} = createForm({ /*...*/ })
</script>

<!-- only validate on:change under specific conditions -->
<input 
	use:validateOn={[$state.myField.touched ? 'change' : null]}
	on:change={handleChange}
/>

larrybotha avatar Jul 11 '20 05:07 larrybotha

The alternative would probably be to specify the events to run validation on as an argument of the createForm function, but I prefer the usage of actions for dynamically changing the conditions under which validations run. @larrybotha what events do you have in mind to support for validateOn? Support for mount might be a nice addition https://formik.org/docs/api/withFormik#validateonmount-boolean

tiaanduplessis avatar Jul 13 '20 11:07 tiaanduplessis

@tiaanduplessis to keep things flexible we could allow the user to pass in any DOM event and add / remove listeners dynamically:

// svelte-forms-lib/lib/actions.js
const validateAction = (node, {events} = {events: ['change']) => {
	let activeEvents = [];

	function addListeners(events) {
		activeEvents = events;
		activeEvents.map(event => node.addEventListener(event, validate);
	}
	
	function removeListeners() {
		activeEvents.map(event => node.removeEventListener(event, validate);
	}

	addListeners(events)

	return {
		update(({events}) {
			removeListeners();
	
			addListeners(events);
		},
		
		destroy() {
			removeListeners();
		}
	}
}

If an invalid event DOM event is passed, then it's no biggy - nothing happens.

validateOnMount may be nice as a separate action to separate it from DOM events:

	<input
		use:validateOnMount
	/>

EDIT: validateOnMount is applicable on https://github.com/tjinauyeung/svelte-forms-lib/issues/20, but now we're getting into field vs form-level actions

larrybotha avatar Jul 13 '20 13:07 larrybotha

I've started using https://github.com/ukchukx/svelte-inline-input and now I'm looking at ways how to use svelte-forms-lib with it as well: https://github.com/ukchukx/svelte-inline-input/issues/3

It's using on:blur in particular to be notified of user input: https://medium.com/@ukchukx/creating-an-inline-input-component-in-svelte-and-publishing-to-npm-84274be1aa73

evdama avatar Aug 27 '20 05:08 evdama