shoelace icon indicating copy to clipboard operation
shoelace copied to clipboard

<sl-input> 'invalid' property is updated after the 'sl-input' event is dispatched

Open fabricedesre opened this issue 2 years ago • 2 comments

Describe the bug

Checking the input.invalid property in a sl-input event handler does not always return the correct value, because internally the invalid property is updated after the event is dispatched.

To Reproduce

Use the following html:

<sl-input label="What is your name?" minlength=3></sl-input>

and JS:

let input = document.querySelector("sl-input");

input.addEventListener("sl-input", () =>  {
 console.log(`Input value=${input.value} invalid=${input.invalid}`);
});

fabricedesre avatar Aug 30 '22 02:08 fabricedesre

@claviska any hint on how to fix that?

fabricedesre avatar Sep 10 '22 00:09 fabricedesre

A workaround looks like this:

let input = document.querySelector('#boom');

input.addEventListener('sl-input', async () => {
  await input.updateComplete;
  console.log(input.invalid);
});

This is a lifecycle issue and I'm debating a couple ways to solve it, as it isn't unique to <sl-input>. One idea is to create a deferred emitter that waits until the update is complete before firing off the event. The question is should that be the default behavior for most/all events or not.

A proper fix for this requires more analysis and testing. Thanks for your patience!

claviska avatar Sep 12 '22 13:09 claviska

This is a non-issue as of 2.0.0-beta.84 because the invalid attribute has been removed. Instead, you should use the SlInput.checkValidity() method, which works exactly like HTMLInputElement.checkValidity() and always returns the current validity of the internal input.

This was a breaking change that applies to all form controls. In addition, the following validity "states" are applied to all form controls that allow you to customize them more like native form controls.

Learn more Custom Validation Styles on this page

An updated example would look like this:

<sl-input 
  label="Enter your name"
  help-text="Check the console to see validity"
  minlength="3"
></sl-input>

<script>
  const input = document.querySelector('sl-input');

  input.addEventListener('sl-input', () =>  {
   console.log(`value: ${input.value}\ninvalid: ${!input.checkValidity()}`);
  });
</script>

Try it on CodePen

claviska avatar Dec 08 '22 17:12 claviska

Thanks for the heads up!

Unfortunately it looks like the validation styles (data-user-* attributes) are not set properly. If you add a minlength = "8" attribute to the example you'll see that it is considered valid from a styling point of view as soon as a character is typed in, even though checkValidity() returns the expected value taking the constraints into account.

fabricedesre avatar Dec 08 '22 18:12 fabricedesre

I opened https://github.com/shoelace-style/shoelace/issues/1063 as a follow-up

fabricedesre avatar Dec 08 '22 20:12 fabricedesre

Thanks. One of the things on my list is to add tests for all those validation states for each form control. I was hoping to have them done already, but it was quite a chore to get everything updated and I ran out of time that day.

I'll take a look at this one tomorrow!

claviska avatar Dec 08 '22 20:12 claviska