Elements with #has_garbage_value and #value are always set as a triggering element

Created on 24 February 2012, over 13 years ago
Updated 27 June 2023, about 2 years ago

When two buttons are added to a form, one vanilla HTML button and one image button, $form_state['triggering_element'] is always the image button regardless of which button is clicked. If both buttons are HTML buttons then the triggering element is set properly. If both buttons are image buttons, the last button in the form will be the triggering element. This is true when using both ajax and normal submit.

In order to demonstrate, I have created a content type called "test" and used the following code for the buttons and their ajax callbacks.

<!--break-->
/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_form_test_node_form_alter(&$form, &$form_state, $form_id) {
  $form['html_button'] = array(
    '#type' => 'button',
    '#value' => 'HTML button',
    '#ajax' => array(
      'callback' => 'mymodule_button_html_callback',
      'wrapper' => 'mymodule_replace',
    ),
  );

  $form['image_button'] = array(
    '#type' => 'image_button',
    '#value' => 'Image button',
    '#src' => drupal_get_path('module', 'mymodule') . '/image.jpg',
    '#ajax' => array(
      'callback' => 'mymodule_button_image_callback',
      'wrapper' => 'mymodule_replace',
    ),
  );

  $form['#prefix'] = '<div id="mymodule_replace">';
  $form['#suffix'] = '</div>';
}

/**
 * Callback function for the HTML button's ajax event.
 */
function mymodule_button_html_callback(&$form, &$form_state) {
  drupal_set_message('HTML button');
  return $form;
}

/**
 * Callback function for the image button's ajax event.
 */
function mymodule_button_image_callback(&$form, &$form_state) {
  drupal_set_message('Image button');
  return $form;
}
๐Ÿ› Bug report
Status

Closed: outdated

Version

9.5

Component
Formย  โ†’

Last updated 6 days ago

Created by

๐Ÿ‡บ๐Ÿ‡ธUnited States BassistJimmyJam

Live updates comments and jobs are added and updated live.
  • DrupalWTF

    Worse Than Failure. Approximates the unpleasant remark made by Drupal developers when they first encounter a particular (mis)feature.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    Thank you everyone for this.

    Closing as outdated as there hasn't been a follow up for #22

    If still a bug please reopen updating issue summary for D10

    Thanks!

  • Status changed to Needs work about 1 month ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA

    This is absolutely still a bug in Drupal 11.

    Button Field module documents:

    Important note

    Due to #1452894: Elements with #has_garbage_value and #value are always set as a triggering element you can not use image buttons on edit forms when there are any other buttons. Non-editable displays are unaffected.

    And where i'm coming from, i confidently told Gin in ๐Ÿ› Image buttons cannot be kept in Gin's sticky form actions Active that core's image button form element is a valid alternative to a standard submit input form element:

    As noted in โœจ UX when using gin with Contnet Moderation and Workflows Active , Workflow Buttons module pairs very well with Gin for improving the experience of using content moderation workflows, and the 2.0.x branch of Workflow Buttons' "Trash workflow" submodule switches to using the image button to have a trash icon for the soft-delete, similar to the trash icon Claro/Gin add to core's delete link. [โ€ฆ]

    But in short swapping the submit button out and substituting an image button for it works, and Gin should support this core form element when adding Gin attributes and looking for the #gin_action_item flag.

    And i get it working perfectly and then discover that no matter which button i press, the image button (soft delete!) is the one that gets incorrectly identified as the trigger button.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA

    And it is not a duplicate with changing values client side; although that may be related, this is being caused with alteration in a Drupal form/widget alter.

  • Pipeline finished with Failed
    about 1 month ago
    Total: 478s
    #563931
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA

    Essentially the fix by wojtha in this issue 13 years ago and richthegeek and cvangysel in #873070: When an image button appears after another button in a form, the wrong triggering element and #submit handlers are detected โ†’ 14 years ago remains correct and needed.

    When image buttons are clicked, browsers do not set NAME in the POST, instead setting NAME_x and NAME_y (with x and y the coordinates of the click). To get the clicked button we need to test for these parameters instead of the presence of valueโ€” that is, equally . (Damien's suggestion of using #value for image buttons also does not work, whether the button is pressed or not, whether it has a value or not, the value gets set anyway, and set to "true", presumably because of how image buttons are treated by the browserโ€” the only thing that is safe to check are if coordinates were set.)

    And yes (replying to 13 year old comments from another issue now, but the same feedback will come up) these changes make the alternative condition specific to image buttons, but i'm fairly certain that is because that is all there isโ€” the only other element in core which uses #has_garbage_value is Radios, which aren't ever going to be triggering a form submission.

    So, yeah, image buttons are ridiculous and Drupal core could totally deprecate them and not support them since basically nobody has cared for a decade (especially if we finally do ๐Ÿ“Œ Use form element type instead of Needs work ), but as long as we have ImageButton extending Submit we need to support it properly as an alternative to Submit, that works alongside Submit buttons.

    The merge request is ready and works, but leaving Needs work as it needs a test showing that this fails even when value is not set in the initial form element definition. As my use case is altering an existing button there is some possibility that something about that is adding 'value' back, but definitely unsetting value is not enough.

Production build 0.71.5 2024