Problem/Motivation

As per this very old forum discussion, creating form element buttons with a type of anything other than type="submit" is not possible - type="submit" is hard-coded.

Steps to reproduce

Proposed resolution

Add an additional #submit_button key to #type button, defaulting to TRUE. When this is FALSE, remove the type=submit related logic from the output.

Remaining tasks

Create a failing functional test that the MR makes pass. If possible utilise one of the existing test forms. Also try to add the test to an existing test class.

Since this change affects the submit #type indirectly, update docblocks and comments on submit and button #types accordingly.

Create a new child issue: demonstrate the new #submit_button key in the examples project's form API module.

User interface changes

N/A

Introduced terminology

N/A

API changes

A new key '#submit_button' is added to the button form #type. The default value is TRUE. That preserves the current behaviour of the button #type for backward-compatibility reasons. However, if changed to FALSE, the button element will no longer submit when clicked. Clicking will not trigger a page refresh.

Data model changes

N/A

Release notes snippet

The change allows the developer to toggle off form submission functionality with one line of code and no need to resort to multi-line workarounds.

Issue fork drupal-289240

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Ryan Palmer’s picture

Title: Button form element doesn't allow for anything but type="submit" » Button element doesn't allow anything but type="submit"

Shorter title... hopefully more eyeballs.

dman’s picture

Is this the problem you are addressing?
http://drupal.org/node/72855

There is a discrepancy between what Drupal API thinks is a form '#type'=>"button" element and what HTML thinks is a form type="button" element. :(

If you create a '#type'=>"button" you actually get <input type="submit"> which sends the form back to the server but the Drupal FAPI doesn't actually run the submit code :-}
You do not get <input type="submit"> in any way. This is a huge terminology disconnect.

There still is, AFAIK, no supported way to add a proper HTML 'button' or 'reset' element other than by having it into #markup

The PROBLEM however is that it's now basically impossible to switch back to making Drupal-button == HTML-button as all throughout the codebase 'buttons' are being used to submit (and preview and validate). See the discussion above. Unfortunately this means your patch will KILL a large part of current Drupal functionality!

The API ref could probably have better documentation explaining that even 'buttons' are submitted to the server.
And we could add a new type of 'button' to actually produce HTML buttons to disambiguate. ... Although it may have the opposit e effect.

I've learnt to live with the idea that actionless buttons are not a Drupal server-side job, and that 'reset' buttons are entirely useless. So since then I've not needed other button types. Except for AJAX, and this just forces me to keep my Javascript "unobtrusive"... although it's still awkward at times.

Ya see what I'm saying ? :-{

Ryan Palmer’s picture

Status: Active » Closed (duplicate)

I see what you're saying, and my bad for not digging a bit deeper before posting this issue.

So should this issue be refocused as "Change all those damn submit buttons in Drupal to the way they were meant to be written"? :)

Marked as duplicate.. will pick up with the original issue.

dman’s picture

The change ain't going to happen, as there IS a significant use for the send-data-to-server-but-don't-run-FAPI-submit drupal button. It's very widespread. And useful as it is.
HTML type=button buttons basically do absolutely nothing without javascript. And are used very rarely.

A clarification that (button != button) and work-around in the documentation is the most likely way forward.

.dan.

David Stosik’s picture

And what about the reset button, which may be needed in some forms, but still impossible to create other than using #markup?

Thanks,
David

dman’s picture

The reset button is an un-feature ... especially in the days of AJAX and multi-step forms.

ro-no-lo’s picture

I am not quite with you. I for myself would like to have an button, where I can attach javascript events which does absolutly nothing, when JS is not enabled. I.E. does not submits the form.

This might be an usability issue, but this can be solved via text or so.

To have an simple example. I would like to populate one form from anthoer as a little helper. (textarea lines into multiple textfields). This costs me 20 lines of JS or so and is much harder on the server side because the textfields are CCK managed and I don't want to manually hack there something. At least at first.

visum’s picture

Looks like a mostly dead discussion at this point, but here are my two cents:

I agree with those who think FAPI should let us make a element.

There are instances in which we like to use FAPI to describe and render forms, but do not need the fancy submit handling and such. For example, I've got a form I'm working on now that simply use jQuery to read the field values and generate Google Maps directions. No submit needed or wanted. I suppose the markup type can be used, but FAPI seems somewhat incomplete without the ability to generate all of the useful form elements.

damien_vancouver’s picture

I found a great workaround for this in Drupal 7, thanks to This StackOverflow question. To quote from the answer there:

You can use:

$form['my_button']['#executes_submit_callback'] = FALSE;

To disable the "submit" step.

If you only want to disable the "validate" step, use:

$form['my_button']['#limit_validation_errors'] = array();

This appears to be contrary to what the handbook page Howto: Taming the Form Buttons. has to say. I suspect that the behavior may have changed for Drupal 7?

Anyway, it worked great for me when I added both in there. My use case is I added a button in hook_form_alter, which is supposed to fire off an #ajax callback. So obviously I don't want it validating nor do I want it submitting the form.

whatsmyline’s picture

Wow, this issue is absurd. I want this fixed so badly. I TOTALLY agree with the OP.

  1. Dont call it a #button_type if it doesn't effect the freaking button's 'type.'
  2. Don't call it a 'button' when it can be nothing except a 'submit button.' Calling it a 'button' implies that it could be more than one type of button.
coredumperror’s picture

Category: bug » feature
Status: Closed (duplicate) » Active

I also agree with whatsmyline, and the OP: it is unacceptible that there's no way to create an <input type='button'> element without using #markup, since doing so rules out using the majority of the awesomeness from the Forms API.

However, since the existing #type => 'button' does have a legitimate use, maybe you could implement a new one, like '#type' => plain_button?

This inability to create non-submit buttons is a major UX issue for module writers who want to make forms with more than one button. Since every button is automatically a 'submit', pressing Enter while a form field is focused causes the first button in the form to be executed, rather than the actual form submission button (e.g. the OK button). By allowing us to make <input type='button'> elements, we can control which button the browser submits when the user presses Enter.

andypost’s picture

Version: 6.x-dev » 8.x-dev

Suppose related #1719640: Use 'button' element instead of empty links

This require now to just write a new theme_button() function, change a process callback and fix render tests

  $types['submit'] = array(
    '#input' => TRUE,
    '#name' => 'op',
    '#is_button' => TRUE,
    '#executes_submit_callback' => TRUE,
    '#limit_validation_errors' => FALSE,
    '#process' => array('form_process_button', 'ajax_process_form'),
    '#pre_render' => array('form_pre_render_button'),
    '#theme_wrappers' => array('input__submit'),
  );
  $types['button'] = array(
    '#input' => TRUE,
    '#name' => 'op',
    '#is_button' => TRUE,
    '#executes_submit_callback' => FALSE,
    '#limit_validation_errors' => FALSE,
    '#process' => array('form_process_button', 'ajax_process_form'),
    '#pre_render' => array('form_pre_render_button'),
    '#theme_wrappers' => array('input__button'),
  );
jbrown’s picture

Title: Button element doesn't allow anything but type="submit" » There is no way to make a button element that can use the AJAX functionality
Category: Feature request » Bug report
Related issues: +#72855: form #type 'button' does not work as advertised - it's always a submit

This really is a pain in the ass.

type="submit" input elements cause all sorts of browser activity such as trying to remember passwords elsewhere in the form, etc.

You can use '#type' => 'markup', but then you loose all the AJAX functionality.

Maybe we should be able to specify '#element_type' ?

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.

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.

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

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should 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.

vomitHatSteve’s picture

Seems to me the solution here is to make it so that bad defaults don't forcibly override user-supplied values.

Attached is a patch that makes buttons respect the "type" attribute if provided.

Ostensibly, this shouldn't break any existing functionality that depends on the default behavior.

andypost’s picture

Version: 8.4.x-dev » 8.5.x-dev
Status: Active » Needs review

Start CI on patch

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.

darvanen’s picture

I'd call #18 a workaround rather than a solution, but considering how damn long this problem has existed - I think it's definitely worth doing, at least in the short term.

The form API has both 'submit' and 'button' types, I really don't think buttons should automatically submit the form.
What is stopping us from setting the default of a 'button' element to type="button"? Or even just making '#executes_submit_callback' = FALSE work somehow?

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.

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.

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.

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

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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.

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

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

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

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.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.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.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.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now 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.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now 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.

seanb’s picture

Another thing to consider is that the first element with input type submit is triggered when pressing the enter key in any of the form fields. See the list of issues related to this. Using <input type="button"> for AJAX buttons would solve this.

#2483505: Not possible to submit forms with pressing ENTER, if form has a file field
#212423: Standardize form submission behavior when "enter" key is pressed
#927176: "Enter" key removes file instead of saving node
#2030659: Disable 'enter' submission on extend page
#472698: admin/settings/performance: Keyboard <enter> key clears cache instead of applying settings
#2103017: Pressing the enter key in a variety of fields triggers form submit
#2785283: Enter key press in autocomplete results lead to ajax form submission
#1264794: Views exposed autocomplete + ajax view = form submit happens too early
#2897855: Entity browser modal dialog opens by pressing enter in any text field

Not sure how we can do this in a backward compatible way? I guess we need to introduce a new render element for it, and officially promote that so modules implementing AJAX buttons can start using it.

How about adding a new #type = 'ajax_button' element for this purpose?

darvanen’s picture

#31 sounds sensible to me.

smustgrave’s picture

Hiding #18

#31 does sound like a good approach. Tagging for framework managers for their thoughts.

Once that's decided the issue summary would need to be updated.

larowlan’s picture

#9 seems to be the way forward here, is this just a docs issue?

larowlan’s picture

Status: Needs review » Postponed (maintainer needs more info)
Issue tags: -Needs framework manager review

Version: 10.1.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, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

darvanen’s picture

@larowlan the documentation states that #buttons don't trigger the submit handler. Do we change the documentation or update the API to meet what seems to be the original intent?

larowlan’s picture

tbh I'm not sure, I don't use #type button very often

seanb’s picture

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

I don't think #9 fixes the issue. The problem is in the browser. When pressing the enter key, the first input element with type "submit" is triggered, instead of the actual form submit button. We should really stop using type "submit" for AJAX buttons, since they are not the primary form submit button. This is caused by the fact that Drupal\Core\Render\Element\Button always uses "submit" as the button type.

So we either need to add a new setting to allow changing the button type, maybe a key like #submit_button?

 $form['ajax_example'] = [
   '#type' => 'button',
   '#submit_button' => FALSE,
   '#value' => $this->t('My AJAX button'),
 ];

Or another render element that always uses the button type. Something like #type = 'ajax_button' (although it is not necessarily always going to be used for AJAX stuff).

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Didn't see a patch to review

But was previously tagged for issue summary update which I'm sure is still needed. Plus when a patch is there will need a test case

darvanen’s picture

Thanks @smustgrave :)

#39: @seanB it would seem at the moment that Drupal's take on an AJAX button is that its sole purpose is to trigger a backend handler on the form, be it the submit handler or a different method (and therefore the advice to simply turn off the submit handler).

How do we make the case for buttons which don't send anything to the backend at all? I think that would be the easiest one to get support behind. And from there we can talk about how to do it.

I've lost track of what I was trying to do when I came across this issue.

Perhaps we could make a contrib module which demonstrates the issue and will give us a measurable indicator of demand (beyond how few concerned people have found this ticket)?

seanb’s picture

Well, the list of issues in #31 is a pretty big indicator that people are struggling with problems because of the fact that it is impossible to create an <input type="button"> at the moment. Of course, we could do this in contrib, but that would mean all modules that have AJAX buttons would need a dependency on this new module to solve the issue.

Adding a flag like #submit_button to the existing button element would probably be the easiest and most developer friendly way to solve this. So I'm hoping this is a thing we could add to core.

smustgrave’s picture

Possible to get the issue summary update or a test case?

catch’s picture

Title: There is no way to make a button element that can use the AJAX functionality » Allow #type 'button' that aren't form submits
Category: Bug report » Task
Issue summary: View changes
Issue tags: -Needs issue summary update

I think #submit_button defaulting to TRUE is a good idea here, it would be backwards compatible and less confusing than having two button elements.

This is a small API addition rather than a bug IMO, so reclassifying as a task. Also re-titled and updated the issue summary.

oily’s picture

oily’s picture

Issue summary: View changes
oily’s picture

Issue summary: View changes
oily’s picture

I am testing in the browser via the Drupal UI the current 'fix' now committed to the issue fork. I am testing using the 'simple form' in the examples project forms api module.

With the #submit_button left at default TRUE the html is:
<input class="button--primary button js-form-submit form-submit" data-drupal-selector="edit-submit" type=“submit” id="edit-submit" name="op" value="Do Not Submit!">

With the #submit_button set to FALSE:
<input class="button--primary button js-form-submit form-submit" data-drupal-selector="edit-submit" type="button" id="edit-submit" name="op" value="Do Not Submit!">

Note that the class attributes 'js-form-submit' and 'form-submit' are left unchanged. The 'type' attribute IS changed which seems the only requirement for the purposes of this issue. If anyone sees a good reason to change the class attributes please comment!

Otherwise the task of writing a failing functional test should be straightforward.

oily’s picture

The Forms functional tests are extensive and it is tricky to work out the best place to put this test. I have arrived at the idea of creating one or two new test forms with only 2 or 3 form elements defined. Then insert a new test function (or 2) in the ElementTest test class and assert that the 'type' attribute contains 'button' or 'submit' using the 'xpath' selector type..

oily’s picture

Status: Needs work » Needs review

The test created under this ticket ElementTest::testSubmitButtonAttribute is passing.

smustgrave’s picture

Status: Needs review » Needs work

Left comments on MR.

oily’s picture

For some reason my local phpunit is ignoring the functional test method introduced by the merge request. Troubleshooting this now. phpunit was executing the test method fine until the most recent batch of commits.

Not sure maybe my local phpunit config is wrong. I mean if the gitlab pipeline is passing the phpunit functional tests, that is canonical?..

Okay sussed it out: running 'vendor/bin/phpunit -c core --filter=testSubmitButtonAttribute' does not work.

'vendor/bin/phpunit -c core --filter=testFormElements' works. It is the correct command to use locally. But it just happens to be the way the tests are (intentionally) configured. Nothing amiss.

oily’s picture

Status: Needs work » Needs review
darvanen’s picture

Status: Needs review » Needs work

I'm so happy to see some traction on this and buy-in from @catch. The approach looks good to me, I think we just need to tidy a few things to grease the wheels.

oily’s picture

@darvanen Your suggestions look good.

oily’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Threads about the 80 character wrapping still seem to be needed.

oily’s picture

@smustgrave @darvanen I have reacted to the code comments re the 80 character limit. Changing back to Needs review

oily’s picture

Status: Needs work » Needs review
oily’s picture

Issue tags: -Needs tests
oily’s picture

oily’s picture

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
1) Drupal\Tests\system\Functional\Form\ElementTest::testFormElements
Behat\Mink\Exception\ExpectationException: 0 elements matching xpath "//input[@type="button"]" found on the page, but should be 1.
/builds/issue/drupal-289240/vendor/behat/mink/src/WebAssert.php:888
/builds/issue/drupal-289240/vendor/behat/mink/src/WebAssert.php:441
/builds/issue/drupal-289240/core/modules/system/tests/src/Functional/Form/ElementTest.php:161
/builds/issue/drupal-289240/core/modules/system/tests/src/Functional/Form/ElementTest.php:35
FAILURES!
Tests: 1, Assertions: 74, Failures: 1.
Exiting with EXIT_CODE=1

Shows the test coverage

Also resolved the threads because they appeared to all be addressed.

I did not find anything else pending and code looks fine to me.

Going to mark it.

quietone’s picture

Status: Reviewed & tested by the community » Needs work

I read the IS, comments and the MR. I think two comments need to be improved. I did one but the other I wasn't sure what to add so setting this to needs work for those comments.

oily’s picture

Replaced comments with suggestion of @trackleft2.

Rebased.

oily’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Believe feedback has been addressed

catch’s picture

Issue tags: +Needs change record

I think this could use a change record for the small API addition.

smustgrave’s picture

quietone’s picture

catch asked me to check in here.

Thanks for improving the comments! It is much clearer and easier for developers to understand how to use this. The description for '#submit-button' doesn't follow our practice, where the default is at the end. For example, 'When FALSE this happens. Defaults to TRUE'. But it is not a standard and more importantly, the information here is correct. That should not delay this improvement.

Leaving at RTBC

  • catch committed c0b7af82 on 10.5.x
    Issue #289240 by oily, vomitHatSteve, smustgrave, darvanen, Ryan Palmer...

  • catch committed 174c76f4 on 11.x
    Issue #289240 by oily, vomitHatSteve, smustgrave, darvanen, Ryan Palmer...
catch’s picture

Version: 11.x-dev » 10.5.x-dev
Status: Reviewed & tested by the community » Fixed

Committed/pushed to 11.x, thanks! Also cherry-picked to 10.5.x for API parity.

Status: Fixed » Closed (fixed)

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

boulaffasae’s picture

.