Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calcite input validity, validationMessage, and willValidate properties #7413

Open
2 of 3 tasks
nwhittaker opened this issue Aug 1, 2023 · 6 comments
Open
2 of 3 tasks
Assignees
Labels
1 - assigned Issues that are assigned to a sprint and a team member. ArcGIS Field Apps Issues logged by ArcGIS Field Apps team members. blocked This issue is blocked by another issue. calcite-components Issues specific to the @esri/calcite-components package. enhancement Issues tied to a new feature or request. impact - p2 - want for an upcoming milestone User set priority impact status of p2 - want for an upcoming milestone p3 - want for upcoming milestone User set priority status of p3 - want for upcoming milestone spike Issues that need quick investigations for time estimations, prioritization, or a quick assessment.
Milestone

Comments

@nwhittaker
Copy link
Contributor

nwhittaker commented Aug 1, 2023

Check existing issues

Description

Native <input> elements implement the Constraint Validation API. Various attributes indicate which types of values are considered valid and which are invalid (e.g. required, pattern, min, max, etc…). The <input> uses a validity property (of type ValidityState) to expose if its value is valid or, if not, the reason why the value is invalid. This property is updated internally every input event. Useful validationMessage and willValidate properties also exist. See API doc for these properties.

If Calcite inputs similarly exposed validity and willValidate properties, it would offload much of the redundant validation logic the consumer currently has to perform in order to figure out which error message to show. Exposing the validationMessage property could also alleviate the need for exhaustive string translations.

The API exposes other helpful functionality such as checkValidity(), reportValidity(), setCustomValidity(), and the invalid event -- however, implementing these probably wouldn't get us much until Calcite inputs render their own error messages.

Blocked issues: #8126

Acceptance Criteria

  1. Calcite inputs expose a validity property of type ValidityState that always reflects the validity of the input's current value.
  2. Calcite inputs expose a validationMessage property that always reflects the reason for why an input is invalid.
  3. Calcite inputs expose a willValidate property that always reflects whether the input should report its validity.

Relevant Info

I suspect the implementation could be as simple as passing through the underlying <input> element's validity, validationMessage, and willValidate properties. For a more feature-complete implementation, consider converting Calcite inputs to form-associated components once Stencil supports them.1

The Field Apps web team is planning a rewrite of the form-editing experience this Fall. This UI includes complex validation rules that could be simplified by offloading some of the more agnostic validation logic to the Calcite input elements.

Which Component

All Calcite inputs.

Example Use Case

const calciteInput = document.querySelector('calcite-input');
const calciteInputMessage = document.querySelector('calcite-input-message');

calciteInput.addEventListener('calciteInputInput', () => {
  // Give user a chance to fill in an initially valid value before triggering greedy validation messaging.
  if (calciteInput.status === 'idle') return
  validate();
});

calciteInput.addEventListener('calciteInputChange', () => {
  // Avoid redundant validation if last `calciteInputInput` event already ran it.
  if (calciteInput.status !== 'idle') return
  validate();
);

function validate() {
  const status = calciteInput.validity.valid ? 'valid' : 'invalid';

  calciteInput.status = status;
  calciteInputMessage.status = status;

  if (calciteInput.validity.valueMissing) {
    calciteInputMessage.textContent = 'A value is required';
  } else if (calciteInput.validity.rangeUnderflow) {
    calciteInputMessage.textContent = 'Your value is too low';
  } else if (calciteInput.validity.rangeOverflow) {
    calciteInputMessage.textContent = 'Your value is too high';
  } else {
    calciteInputMessage.textContent = calciteInput.validationMessage;
  }
};

Priority impact

p3 - want for upcoming milestone

Calcite package

  • @esri/calcite-components
  • @esri/calcite-components-react

Esri team

ArcGIS Field Apps

Footnotes

  1. https://github.com/ionic-team/stencil/issues/2284

@nwhittaker nwhittaker added enhancement Issues tied to a new feature or request. 0 - new New issues that need assignment. needs triage Planning workflow - pending design/dev review. labels Aug 1, 2023
@github-actions github-actions bot added p3 - want for upcoming milestone calcite-components Issues specific to the @esri/calcite-components package. ArcGIS Field Apps Issues logged by ArcGIS Field Apps team members. labels Aug 1, 2023
@JonnyDawe
Copy link

Our team also encountered this issue and ended up having to refactor or add in clunky logic to target the inputs inside of the custom calcite input elements. This would be a great feature to have.

@nwhittaker nwhittaker changed the title Calcite input validity property Calcite input validity and validationMessage properties Aug 4, 2023
@nwhittaker nwhittaker changed the title Calcite input validity and validationMessage properties Calcite input validity, validationMessage, and willValidate properties Aug 9, 2023
@nwhittaker
Copy link
Contributor Author

It looks like support for form-associated components landed in Stencil 4.51

Footnotes

  1. https://ionic.io/blog/announcing-support-for-form-associated-custom-elements-in-stencil-v4-5-0

@benelan
Copy link
Member

benelan commented May 1, 2024

Safari needs to support elementInternals for one more version before the API adheres to Calcite's system requirements.

However, the recent v2.8.0 release of Calcite components includes a partial implementation of the validation constraint APIs, which should have all the essentials! A couple notes:

  • The readonly validity property exposes the ValidityState as you'd expect.
  • The validationMessage property is mutable in place of a setCustomValidity() method.
    • Setting validationMessage does not prevent form submission on it's own like setCustomValidity() does. This allows for setting custom messages on simple forms without the need for javascript (example).
  • Setting the status property to "invalid" will display the validationMessage.
  • The calciteInvalid event is emitted when a form is submitted with invalid value(s).
  • The browser-defined validation message for a constraint is displayed during form submission if validationMessage is not set.
  • Normally, the browser uses checkValidity() to set the :valid, :invalid, etc. pseudo-classes. However, that didn't work with our current form implementation, potentially due to the async nature of Stencil's methods. For now you can style invalid components with an attribute selector, e.g., calcite-input [status=invalid] { ...

Here is a complete demo of the new features:
https://codepen.io/benelan/pen/oNOORrB?editors=0010

Calcite will transition its form implementation to elementInternals once there is full support.

Let me know if you have any questions or concerns as you start testing the new functionality!

@nwhittaker
Copy link
Contributor Author

Thanks for the update @benelan!

It looks like a lot of this will be very beneficial to Field Maps. Not sure what's on the roadmap or how transitioning to elementInternals impacts things, but here's some initial questions/concerns/observations with the current behavior:

  • I see validation only works if the component has a name prop and is within a <form> element. Any plans for supporting validity for standalone components outside of a form?
  • Any plans for a public API to support programmatically submitting or resetting a form? Maybe something like a <calcite-form> component? We have components with public save() methods that we'd like to serve as the means for initiating the submission.
  • Any plans to add support for customError validity? If not, one concern is then with juggling validity across both status and validity props. It leaves the component with no single, atomic, source-of-truth for its validity state. I can see this making it hard to reason about a component that has a valid validity but an invalid status.
  • The architecture appears to be optimized for the scenario of filling out an empty form. I say this because validity syncing is deferred until after the first form submission. However, one of our use-cases is for using a form to edit existing data. In the event the data contains invalid values, it'd be useful to be able to use the validity props to identify those values and give them an initial validation message so the user knows where to make corrections.

Codepen reference implementation

  • Just curious if you had any reason to prefer the blur event over the change (or input) events?
  • The pattern constraint shouldn't need to be wrapped in ^ and $ since the native behavior is to match against the entire value.
  • The minlength and maxlength constraints should be renamed min-length and max-length.

Possible bugs

Happy to create issues for any of these.

  • The min-length and max-length constraints aren't applied in the calcite-input-text component. Editing a value should be updating the tooLong and tooShort validities accordingly, but is not.
  • The native validationMessage can't be restored:
    1. Given a component that violates a native constraint, I see the native validation message by default.
    2. If the user violates a custom error, I set a custom validationMessage and I see the custom message.
    3. If the user fixes the custom error, I empty validationMessage and see no validation message. However, if the component still violates the constraint from step 1, I'd expect to see the native validation message reappear.
  • In the codepen, entering a single word into the Your name field and submitting the form results in a "Please enter your name" validation message instead of "First and last name are required using only letters". The "Please enter your name" message should only appear if the value is empty.

@geospatialem geospatialem added impact - p2 - want for an upcoming milestone User set priority impact status of p2 - want for an upcoming milestone and removed p3 - want for upcoming milestone labels May 21, 2024
@geospatialem geospatialem added spike Issues that need quick investigations for time estimations, prioritization, or a quick assessment. 1 - assigned Issues that are assigned to a sprint and a team member. and removed needs triage Planning workflow - pending design/dev review. 0 - new New issues that need assignment. labels Aug 13, 2024
@gavinr-maps
Copy link

gavinr-maps commented Nov 19, 2024

Note that you could get the "valid" attribute in a very old version of calcite, v1.0.0-beta.86: https://codepen.io/gavinr/pen/JjgqVvw?editors=1010 ... I'm not sure exactly when it stopped working.

@github-actions github-actions bot added the p3 - want for upcoming milestone User set priority status of p3 - want for upcoming milestone label Nov 19, 2024
@geospatialem
Copy link
Member

With the transition to Lit from Stencil, Calcite is ensuring stability before proceeding with ElementInternals support, targeting the above in the next upcoming milestone (December 2024).

@geospatialem geospatialem added the blocked This issue is blocked by another issue. label Dec 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1 - assigned Issues that are assigned to a sprint and a team member. ArcGIS Field Apps Issues logged by ArcGIS Field Apps team members. blocked This issue is blocked by another issue. calcite-components Issues specific to the @esri/calcite-components package. enhancement Issues tied to a new feature or request. impact - p2 - want for an upcoming milestone User set priority impact status of p2 - want for an upcoming milestone p3 - want for upcoming milestone User set priority status of p3 - want for upcoming milestone spike Issues that need quick investigations for time estimations, prioritization, or a quick assessment.
Projects
None yet
Development

No branches or pull requests

5 participants