Form cache causes issues with media library widget

Created on 24 December 2024, 15 days ago

Problem/Motivation

Seems to be some issue with the form cache interaction with the media library widget, and possibly other complex widgets. Not sure where the issue is exactly though. The problem is that after clicking the "remove" button in the media library widget to remove an already-selected item, the form builder doesn't know that the remove button was clicked, and it instead assumes the first button in the form was clicked, which could be anything. On a simple node form with just a media library widget, the button it clicks is the "add media" button so the media library selection modal opens up incorrectly.

Steps to reproduce

  1. Clean install of Drupal with the Media Library module enabled
  2. Create a content type with a media reference field with all default settings
  3. Create a node of that type, select a media item (upload one), and save the node
  4. Edit the node and click the "remove" button in the media library widget. Observe the correct behavior of the item being removed and the widget reverting to its original empty state
  5. Don't save the node, reload the form in your browser
  6. Again, click the "remove" button in the media library widget. Observe that instead of removing the item and reverting the widget to its original state, the media library selection modal opens up incorrectly.

If you have a more complex node form, like one with a paragraphs field on it, what might end up happening instead of the media library modal opening is it that the entire media library widget gets replaced with a paragraph form for a paragraph item!

The wrong behavior is because of this code in FormBuilder:

      // If a form contains a single textfield, and the ENTER key is pressed
      // within it, Internet Explorer submits the form with no POST data
      // identifying any submit button. Other browsers submit POST data as
      // though the user clicked the first button. Therefore, to be as
      // consistent as we can be across browsers, if no 'triggering_element' has
      // been identified yet, default it to the first button.
      $buttons = $form_state->getButtons();
      if (!$form_state->isProgrammed() && !$form_state->getTriggeringElement() && !empty($buttons)) {
        $form_state->setTriggeringElement($buttons[0]);
      }

The wrong element is set as the triggering element for the form submission. Why? Because the form object that's being acted on is used a cached version of the form which is missing the "remove" button for the media library widget. After step #4 above, the state of the form without the selected media item is saved to the cache. And that version of the form is used on the next page reload when you try to click the remove button again.

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

πŸ› Bug report
Status

Active

Version

11.1 πŸ”₯

Component

forms system

Created by

πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA

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

Merge Requests

Comments & Activities

  • Issue created by @bkosborne
  • πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA
  • πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA
  • @bkosborne What browser did you test in?

    For me testing locally on latest 11.x dev:

    1. drush si standard -y
    2. drush en media_library
    3. Add image media field to basic page
    4. Create basic page, upload media image, save
    5. Edit basic page
    6. Remove selected media

    On Windows, Chrome 131.0.6778.205, when I reload, the media selection is restored on the page. When I click the remove button again, the media item is correctly removed.

    Also on Windows, Firefox 133.0.3, I can reproduce the issue mentioned in the IS. However, if I revisit the page (while on the page, click in location bar and hit enter) instead of reloading, then the remove button works as expected.

    It seems to be related to Firefox keeping form data on reload: https://stackoverflow.com/questions/7377301/firefox-keeps-form-data-on-r.... It's an old issue on stackoverflow, but I can confirm that if I add the autocomplete="off" attribute to the node form, e.g. $form['#attributes']['autocomplete'] = 'off';, then reloading on Firefox works the same as Chrome.

  • Pipeline finished with Success
    11 days ago
    Total: 442s
    #380004
  • FWIW, making sure the form_build_id hidden input value does not get retained by the browser was enough to fix the issue for me on Firefox. I put up a draft MR 10706 with that change.

  • Pipeline finished with Failed
    10 days ago
    Total: 125s
    #380738
  • Pipeline finished with Success
    10 days ago
    Total: 792s
    #380743
  • πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA

    It didn't occur to me to test in Chrome, thanks for that! I guess due the nature of the issue I didn't think it would be browser specific. Thanks for doing that and the MR! I'll test this next week and report back...

Production build 0.71.5 2024