I fall into problem that if some of buttons changed on client side and form has several submit buttons,
first button will be selected as $form_state['triggering_element'].

There is a related topic for D8 to rely on #name of buttons and ensure that #name is unique within form.
What i want to make with this patch is just backport of same idea.

If button was not identified by #value instead of just take first from buttons, just try to look up within POST data by button's #name if it exists.
Advantage of this approach that all backward compatibility supported.

Comments

IRuslan created an issue. See original summary.

IRuslan’s picture

Attaching patch.

Status: Needs review » Needs work
IRuslan’s picture

StatusFileSize
new1.08 KB

Re-rolling updated patch with proper path.

IRuslan’s picture

Status: Needs work » Needs review
IRuslan’s picture

StatusFileSize
new1.39 KB

Improved version to handle Ajax-triggering elements.

David_Rothstein’s picture

Status: Needs review » Postponed (maintainer needs more info)

Doesn't Drupal 7 already try to identity the triggering element by a combination of both #name and #value, rather than just #value? See _form_button_was_clicked() and _form_element_triggered_scripted_submission(). So it's not obvious to me what scenario this patch would help in.

Also if this is the essentially the same as a Drupal 8 issue, it should be closed in favor of that one so we don't have duplicated discussions. (And #1342066: Document that buttons with the same #value need a unique #name for the form API to distinguish them, or change the form API to assign unique #names automatically is already marked for Drupal 7 backport.)

IRuslan’s picture

Status: Postponed (maintainer needs more info) » Needs review

Hi David,

Actually, you are partially right, Drupal tries to detect clicked button itself.
But as we can see _form_button_was_clicked() rely on #value attribute only.
And _form_element_triggered_scripted_submission() used only for Ajax submissions.

As a result, the next flow will lead to error:
1. We have a form with multiple submit buttons
2. We have some behaviour, which changes the #value of submit button (i.e. label changed by JS for UX reasons or we have translation proxy for a whole site)
3. Then we submit form
4. Triggering element will not be properly detected because an incoming value is different from $element[#value] of built initially built.

From my point of view, details from point 2 above describing general architectural problem of triggering element detection and there are much more cases revealing the issue.

David_Rothstein’s picture

Title: Wrong detection of triggering element on form with several buttons » Wrong triggering element is detected when the clicked button has a unique #name but a label that was changed client-side
Version: 7.x-dev » 8.0.x-dev
Issue tags: +Needs backport to D7

_form_button_was_clicked() relies on both #name and #value matching - but yes, I think I see what you're saying, and how your patch addresses it.

So basically:
1. If a developer creates a unique #name for their form submit button, and
2. It's not the first button on the form, and
2. If the label of the submit button has been changed client-side

Then:
1. Currently Drupal is not smart enough to ever detect that it was clicked.
2. But with your patch, it will be, since it will do a final check to see if something matching the button's #name was submitted (regardless of #value) and use it in that case rather than just blindly falling back on the first form button.

At first glance this makes a lot of sense and I agree it sounds backwards compatible also.

It also sounds different from the other issue, so I agree with keeping them separate. But this would need to be considered for Drupal 8 first and then backported - as far as I can see, Drupal 8 has the same fallback logic in https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Form!FormBuilder.... as Drupal 7 currently does.

IRuslan’s picture

Adopted patch to Drupal 8.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Triss82’s picture

Has this patch been backported to Drupal7? If not where can I see the progress of the backport?

IRuslan’s picture

@Triss82

Initially, I felt into this problem in D7. And this patch works for me — https://www.drupal.org/files/issues/drupal-7.38-fapi_multibuttons_trigge... (attached to issue summary).

IRuslan’s picture

Triss82’s picture

Thanks IRuslan, It was working fine for me also.

vlad.dancer’s picture

Status: Needs review » Needs work

@IRuslan, Thanks too. I will get back here and #1342066: Document that buttons with the same #value need a unique #name for the form API to distinguish them, or change the form API to assign unique #names automatically and #1150006: How to add 'Delete' button using Ajax to a form themed as a table with small module for d8 that reproduce this bug. Confirm that patch works!
About review:

  1. +++ b/core/lib/Drupal/Core/Form/FormBuilder.php
    @@ -1084,7 +1084,22 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
    +            // Try to find an ajax-submitted element by name matched to _triggering_element_name.
    

    Split into two lines to avoid a long string (don't take this file as example of standards)) )

  2. +++ b/core/lib/Drupal/Core/Form/FormBuilder.php
    @@ -1084,7 +1084,22 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
    +              || (!empty($input[$button_element['#name']]))) {
    

    Move ) { on new line

IRuslan’s picture

Status: Needs work » Needs review

Well, I thought about it, but after reviewing current style of FormBuilder.php I saw it's a common manner to write conditions on one line to avoid a pile of parts of conditions.

vlad.dancer’s picture

Ok, I know

When in Rome, do as the Romans do.

So, maybe we can write some tests for that?

tim bozeman’s picture

:)

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joelpittet’s picture

Status: Needs review » Reviewed & tested by the community

This fixed an issue with D7 and seems to be the same patch for D8, Still applies and is quite well documented as to what it's attempting to do.

Pavan B S’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new1.54 KB
new866 bytes
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -1084,7 +1084,22 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
+        // If there was no specific triggering button detected by an element value,

Line exceeding 80 characters
There is one line which is exceeding 80 characters, applying the patch, please review.

joelpittet’s picture

Status: Needs review » Reviewed & tested by the community

Still RTBC

tim.plunkett’s picture

Version: 8.3.x-dev » 8.4.x-dev
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

This needs some test coverage

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dgeezy@gdeezy’s picture

I am working on a module that desperately needed the correct triggering_element to be called because I didn't know the names of the fields as they were being created. #6 worked for my problem, and it's a great relief. Is there any estimate on implementing this into 7 core?

tanc’s picture

Patch in #6 solved the issue for me on a D7 site where AJAX buttons were not behaving properly, the first one was always getting triggered if the buttons were clicked in a specific sequence.

tanc’s picture

I'd like to try writing the test coverage for this but I'm wondering if anyone has a really simple repeatable set of form elements that trigger the problem? If not I'll try and come up with something.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Tilo Schumann’s picture

For me the probem was solved by adding '#name' => 'unique_id' to the button-element ...

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

The test case is having 2 submit buttons with a same value and different names?

NormySan’s picture

Updated Drupal 7 patch to apply properly to 7.64.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

fabianx’s picture

#9 describes the steps needed to write a test.

From a D7 maintainer I am okay with the patch now.

juandels3’s picture

I had this problem in Drupal 8 in a multi-step webform. I happened to use the same value in 2 blocks of 6 buttons each. Each block of 6 buttons I listed it from 1 to 6. Finally, I solved it by adding the attribute #name.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

neograph734’s picture

I have added a test where the submit button is cloned, unique names have been assigned and a unique payload to test for something different than the name.

During submit the value (label) of the submit button is changed.

Status: Needs review » Needs work
neograph734’s picture

Status: Needs work » Needs review

I think this looks ok?

andyg5000’s picture

Status: Needs review » Needs work

At a minimum, this needs a re-roll. I can confirm the bug still exists in core. I have a form with multiple 'button' elements to handle triggering actions other than submitting/saving the form. However, the ajax callback always receives the same triggering element, regardless of which one is actually triggered. Changing the form element to something else, like a 'radio' fixes the issue.

matthiasm11’s picture

I can confirm patch #39 works with D8.8.5. Thanks!

neograph734’s picture

Status: Needs work » Needs review

andyg5000 Could you please explain what has to be re-rolled? The patch still applies to all relevant Drupal versions (I messed up with the PHP versions...). If you were referring to the test-only file; that was supposed to fail.

Setting back to needs review for now. Please change it back if I've overlooked something.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

jefuri’s picture

sgdev’s picture

Patch #46 needs to be the version for further D7 testing and review.

Patch #34 causes a fatal error with Views Data Export batch processing, and returns a 403 Access Denied error. The update in patch #46 fixes this problem.

Thank you to @jefuri for identifying this change.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev
larowlan’s picture

Title: Wrong triggering element is detected when the clicked button has a unique #name but a label that was changed client-side » Add support for detecting the triggering element when buttons are changed client-side
Category: Bug report » Feature request
Issue tags: -Needs tests +Bug Smash Initiative, +Needs issue summary update

This came up as the Bug Smash Initiative daily triage target.

I don't think this is documented as something that the form API supports, so in my mind it is a feature request.

Adding a new title.

Tagging for issue summary update to detail the remaining tasks.

neograph734’s picture

@larowlan, If I am not mistaken this also applied to dropbuttons (possibly generated via AJAX). There is no way to tell what button was pressed. I would say that is a bug.
I will see if I can reproduce a test case for this.

larowlan’s picture

Thanks

neograph734’s picture

I can't replicate the issue I was having with dropbuttons anymore, so that must have had another cause.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new193 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

nickdjm’s picture

So I've been debugging this in 9.5.10 and none of the patches above seem to identify the triggering element properly.

I tracked the issue down to the buttonWasClicked() method in FormBuilder. It specifically checks to see if the name and value of a button is found in the getUserInput() array, but buttons do not submit values. Their value is used as the text to display in the button, if if they are added to the getUserInput() array the value will be an empty string and never match to criteria for marking the button as clicked.

I also noticed that the key for any button on the form will only show up in the getUserInput() array if it was the button used to actually trigger the form submission.

I wrote a patch that adds another check to buttonWasClicked() that checks to see if a button's name is a key in the $input array, and if it is, it flags the button as the one that was clicked and results in the proper triggering element being flagged.

nickdjm’s picture

As a note: I know this needs some work, just wanted to get a patch posted to build upon.

nickdjm’s picture

I have updated the patch in 57 to fix an issue causing views apply/cancel/remove buttons to not submit properly.

The AJAX call _was_ adding a value to the "op" input, so the logic I had in 57 was flawed. We should only assume the input was clicked if the value matches exactly or if the value is exactly empty. Anything other than those 2 outcomes means we can't assume that button was clicked.

nickdjm’s picture

Further testing of both my patch and the previous patch has revealed that properly identifying the clicked button works in some scenarios, but not others.

In the case of my patch, it actually was breaking layout builder's submit buttons because they all have the same name- so disregard my patch.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

abelass’s picture

Hi, is there a patch for d10 available?

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.