payload icon indicating copy to clipboard operation
payload copied to clipboard

Displayed validation error gets stuck

Open phoebejaffe opened this issue 1 year ago • 1 comments

Link to reproduction

No response

Describe the Bug

When the validate function returns an error, it gets stuck showing that first error, even if the user types new content. This is misleading when the user fixes one issue but has another issue that the validation function is catching.

To Reproduce

Set up an input like this and publish to trigger validation on typing. Then type 12345 in the input. When you get to 3, it shows Error number 3 as expected. But then typing subsequent characters doesn't update the displayed error, even though the logs show the validate function returns different errors.

{
  name: `test`,
  label: `Test`,
  type: 'text',
  validate: async (data: string) => {
    if (!data || data.length < 3) {
      return true;
    }
    const errStr = `Error number ${data.length} `;
    console.log(errStr);
    return errStr;
  },
},

Payload Version

2.16.1

Adapters and Plugins

@payloadcms/richtext-slate 1.5.2

phoebejaffe avatar May 17 '24 17:05 phoebejaffe

I can get around this by watching my inputs and manually calling validateForm each time, though this isn't very intuitive as a solution. More context in this discord thread.

function startValidation(formHookResult: ReturnType<typeof useForm>) {
  const { formRef, setSubmitted, validateForm } = formHookResult;
  setSubmitted(true);
  // make sure we have the monaco editor textarea element on the page, and add an event listener
  if (formRef.current) {
    const inputFields = Object.values(formRef.current).filter(
      (el) => el.id === 'field-subject' || el.className === 'inputarea monaco-mouse-cursor-text',
    );
    // if we have inputs, add an event listener on input and call validateForm manually
    if (inputFields.length) {
      inputFields.forEach((field) => {
        // we call validateForm in the next tick so the value has been updated
        field.addEventListener('input', () => setTimeout(() => void validateForm()));
      });
    }
  }
  // if the above failed, do it again in a second
  setTimeout(() => startValidation(formHookResult), 1000);
}

and

// This is an invisible element that exists only to trigger the form's validate-upon-input behavior.
{
  type: 'ui',
  name: 'form-validation-trigger',
  admin: {
    components: {
      Field: () => {
        // `setSubmitted` seems to mainly be for handling the validation behavior of the form on input.
        // By setting to true, the form will validate the fields on input, which is the behavior we want.
        // Otherwise, it only validates on input after clicking "Publish" (Save Draft doesn't trigger validation)
        const formHookResult = useForm();
        startValidation(formHookResult);
        return null;
      },
    },
  },
},

phoebejaffe avatar May 17 '24 17:05 phoebejaffe

@PatrikKozak Any chance we can get a release for v2 in the next week?

phoebejaffe avatar Aug 23 '24 18:08 phoebejaffe

Hey @benjaffe - yup, we'll get a release out for v2 asap!

PatrikKozak avatar Aug 26 '24 17:08 PatrikKozak

@benjaffe v2.27.0 is released with the above fix for this issue.

PatrikKozak avatar Aug 26 '24 18:08 PatrikKozak

Thanks so much @PatrikKozak, and huge thanks for all you do on Payload ❤️

phoebejaffe avatar Aug 26 '24 18:08 phoebejaffe

This issue has been automatically locked. Please open a new issue if this issue persists with any additional detail.

github-actions[bot] avatar Sep 06 '24 20:09 github-actions[bot]