Move form state into the global store

Created on 9 December 2024, about 1 month ago

Overview

At present we track form state (values) using a context provider.
When we load a form into the side panel, this works well because there's a wrapping <drupal-form> element.
However when we update that form via Ajax, we call hyperscriptify on each returned element.
Because these elements aren't initialized with a DrupalForm parent, there's is no context-provider and hence calls to get and set the form state added by inputBehaviors do not work.
In addition - there is a need for form validation to occur on the server side and with the messages maintained only internally to the inputBehaviors HOC, we cannot set them as a result of server-side validation.
Finally, there are use-cases where we would like to be able to commit form state in bulk (i.e. for multiple fields). This cannot be done when we rely on a useEffect hook inside inputBehaviors

Proposed resolution

Move form state to the global store. Keep form state for each form ID separate.
Keep track of both form values and errors in the store.
Make use of this in inputBehaviors

On Drupal side, have routes like the component props form return the value of $formState->getValues() and $form_id along with the HTML response so that RTK can handle bulk committing of values.

These changes block any further work on 🐛 Some components cannot be used in XB because UI prevents SDC props being named `name` Active because of the missing DrupalForm element preventing form state from being set for AJAX returned fields.

User interface changes

📌 Task
Status

Active

Version

0.0

Component

Page builder

Created by

🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @larowlan
  • 🇳🇱Netherlands balintbrews Amsterdam, NL
  • Merge request !459Move form state to redux store → (Merged) created by larowlan
  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    Worked on this at Drupalcon

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    Having some issues with cypress locally. The system module's entity types aren't being discovered when the system module's config is installed

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    This is now passing tests and ready for review

  • 🇺🇸United States effulgentsia

    Looks great to me. Would be good to get @bnjmnm's eyes on this too.

  • 🇺🇸United States bnjmnm Ann Arbor, MI

    EVERYTHING BELOW IS NOT OCCURRING WHEN I RUN E2E TESTS, SO I'M RELUCTANT TO EVEN MENTION IT But this is a big enough structural change that I'm going to document this in case it surfaces something legit. Perhaps something in the e2e test setup is addressing the underlying cause?

    With this branch I see the following as soon as I load any article I visit in XB, new or existing. I also checked on a new Drupal install / different browsers to rule out autosave data messing with things. The screenshot is for the TextField component but I also run into it which other components.
    Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components. Error Component Stack... (see screenshot for the whole darn stack)

    If I pull in a new SDC, the form is not populated with the default values

    Unassigning myself for now, and I'll see if anyone is around to check this on their local.

  • 🇫🇮Finland lauriii Finland

    I can reproduce #9 including on a completely fresh installation. Seems fundamental enough to require additional tests.

  • 🇳🇱Netherlands balintbrews Amsterdam, NL

    The problem is now fixed. I re-introduced maintaining a local state for the input values. This is necessary because we remove the value attribute from the input element in order to avoid getting warnings from React that a controlled component doesn't have event handlers. (See the relevant code in 0.x.) With this attribute removed, reading the value of text inputs on subsequent re-renders — of which we do have a couple — is not possible. Unless we have it saved in a local state.

    I don't fully understand how this was not caught by the tests, but I do have a theory. The only thing I can think of is that the value attribute is there on the initial render, which I was able to confirm via debugging, but I wasn't able to confirm in a way that would actually paint it on the UI. The test code might have been able to get a hold of that value attribute before the component got re-rendered, and deemed the assertion true.

  • 🇳🇱Netherlands balintbrews Amsterdam, NL

    I ruled out my theory for the reason behind the test failures. Adding cy.wait() in those tests doesn't make them fail — it should surface the problem if it was a race condition with the component re-renders.

    Then I remembered something @jessebaker said on Slack: maybe it's a dev vs. production build issue. That's it! 💫

    I was able to confirm that testing the app after npm run build (and reverting my fix) doesn't present the issue! This is because there are no subsequent re-renders occurring for the InputBehaviors component in the production build. They happen in development mode thanks to our use of <StrictMode>, which helps us catch bugs by double rendering in development. That's exactly what happened here. The fix is still valid and necessary.

    I don't see the need for updating our tests: the production build was not broken. Lower-level component tests could test this, but I feel like that would be out of scope for this issue.

  • 🇬🇧United Kingdom jessebaker

    Great debugging @balintbrews. I'm glad my hunch was at least along the right track and helped out some.

    This is a really nice collaboration - nice work everyone.

  • Pipeline finished with Skipped
    about 1 month ago
    #368143
  • 🇳🇱Netherlands balintbrews Amsterdam, NL
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    @balintbrews in #11: wow! 😳 Quite the rabbit hole! And 👏🥳 for #13!!!

    Idea: if we run the UI test suite with both dev and prod builds of the UI, we'd have been able to catch this automatically! Issue + MR: 📌 CI: new `cypress E2E debug` job Active .

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024