Race condition on AJAX change event and form submission

Created on 30 October 2023, about 1 year ago
Updated 9 November 2023, about 1 year ago

Problem/Motivation

The Field UI attaches a change event listener to every form element inside field storage config edit form to update the field config form based on changes made to the storage settings. However, if user submits the form while the change event is still being processed, this leads to a race condition where incomplete or invalid data may be saved.

For example, creating field with a negative value in the Allowed number of values, and directly clicking save button on the form (without unfocusing the field) then the form is successfully saved instead of showing the validation error.

In some cases, such as the list field, this could lead into losing changes made to the options.

Steps to reproduce

  1. Navigate to the add field page of the of any content type.
  2. Select the date type as filed.
  3. Manually enter any negative value in Allowed number of values in the form.
  4. Save the form.

Proposed resolution

The quick fix for this would be to disable the submit button while the AJAX is processing. This would not be the ideal UX but would address the critical data loss issue. We could open a follow-up issue to submit the form without first triggering the change event.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

🐛 Bug report
Status

Fixed

Version

10.2

Component
Field UI 

Last updated 17 days ago

Created by

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

Comments & Activities

  • Issue created by @utkarsh_33
  • Status changed to Postponed: needs info about 1 year ago
  • 🇫🇮Finland lauriii Finland

    I'm wondering if there's a step missing from the steps to reproduce? Tried to follow the steps but it looks like validation is preventing this from happening. Also looked at the code and didn't find anything risky in the field type.

  • Status changed to Needs work about 1 year ago
  • So if we enter any negative value in the given field( which updates the message shown using Ajax) and save the form directly without waiting for the Ajax response then it saves the form even after the message is shown up. I'll write a test to demonstrate this.

  • @utkarsh_33 opened merge request.
  • Status changed to Needs review about 1 year ago
  • Status changed to RTBC about 1 year ago
  • 🇺🇸United States smustgrave

    Rebased to run test-only feature

    1) Drupal\Tests\datetime\FunctionalJavascript\AllowedValuesForDateFieldTypeTest::testAllowedValuesFormValidation
    Behat\Mink\Exception\ResponseTextException: The text "Limit must be higher than or equal to 1." was not found anywhere in the text of the current page.
    /builds/issue/drupal-3397594/vendor/behat/mink/src/WebAssert.php:811
    /builds/issue/drupal-3397594/vendor/behat/mink/src/WebAssert.php:262
    /builds/issue/drupal-3397594/core/modules/datetime/tests/src/FunctionalJavascript/AllowedValuesForDateFieldTypeTest.php:66
    /builds/issue/drupal-3397594/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
    ERRORS!
    Tests: 1, Assertions: 4, Errors: 1.
    

    Which is good.

    Manually testing I can confirm the issue following the steps in the issue summary.
    Applying the MR I was unable to advance the form and got the correct error message.

  • Status changed to Needs work about 1 year ago
  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    Discussed this issue with @lauriii. This issue can cause a problem for list fields where you enter some values in the allowed values and then press submit and they are not saved as you've pressed the submit before the ajax has run. So this causes data loss - hence making it critical.

    I'm not sure about the fix as form.js is loaded on every form.

  • Status changed to Needs review about 1 year ago
  • Status changed to RTBC about 1 year ago
  • 🇫🇮Finland lauriii Finland

    Thanks @Utkarsh_33! I looked into the APIs AJAX system provides and couldn't figure out a better way to do this in the Field UI module. Maybe this is something the AJAX system should handle so that we wouldn't have to override and listen to the AJAX events? Can we file a follow-up to investigate a better solution. This seems fine since it addresses a critical bug.

  • 🇬🇧United Kingdom catch

    Double click prevention was added in 🐛 Double click prevention on form submission Fixed in 2014. There are open issues like #3251249: Should double-click prevention return early when isDefaultPrevented? . I have no idea if that prevention is supposed to work in that situation and is broken, or never worked for it though.

  • 🇫🇮Finland lauriii Finland

    This is different from the double click scenario. This is when you have two events triggered at the same time. This can happen with blur/change event listeners when users clicks a button that triggers the click event. What the MR does is it marks the submit button (in Field UI specifically) disabled while the other AJAX request is triggering to avoid the race condition caused by triggering multiple events at once.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    I think this is good for now - it's a specific fix caused by the issue of have field storage and field config on the same form. I think there is a possible follow up to think about whethere we should prevent all form submission whilst we're ajaxing.

    Committed and pushed 27f9fa664c0 to 11.x and 07830391275 to 10.2.x. Thanks!

  • Status changed to Fixed about 1 year ago
    • alexpott committed 27f9fa66 on 11.x
      Issue #3397594 by Utkarsh_33, lauriii: Race condition on AJAX change...
    • alexpott committed 07830391 on 10.2.x
      Issue #3397594 by Utkarsh_33, lauriii: Race condition on AJAX change...
  • I have opened a follow-up for finding a better(more generic) solution this problem in Find a generic way to resolve race condition on AJAX change event and form submission 🐛 Find a generic way to resolve race condition on AJAX change event and form submission Active .

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024