As mentioned in http://drupal.org/node/80574#comment-129845, recent changes to FormAPI have opened up possibilities for a nice new feature. Currently, form buttons operate in a binary fashion: either they fire the submit callbacks, or they don't.

With this patch, when defining a 'submit' or 'button' form element, one can also set its #submit_suffix property. The default is 'submit', but it could be set to 'delete' or 'send' or any of the above. That value determines what functions will be fired by FormAPI when the button is clicked.

99% of forms don't *need* it, but it's very useful when it is needed. Further explanations as I wake up.

Comments

eaton’s picture

StatusFileSize
new8.31 KB

Here's a slightly updated version of the function that cleans up some cruft in the $submit_values when loads of buttons are included in the form.

Only one code change is necessary with this patch:

function mymodule_form_alter($form_id, &$form) {
  $form['#submit']['my_additional_submit_handler'] = array();
}

becomes:

function mymodule_form_alter($form_id, &$form) {
  $form['#submit']['submit']['my_additional_submit_handler'] = array();
  $form['#submit']['preview']['my_additional_preview_handler'] = array();
  $form['#submit']['delete']['my_additional_delete_handler'] = array();
}

and so on.

chx’s picture

Status: Needs review » Needs work

the distinction between default and additional handlers are unaccaptable. We discussed a solution, we shall see what happens, just updating the issue to proper status.

dries’s picture

I'm not a big fan of the #submit_prefix stuff. I don't think it is actually needed. If you want to implement 'preview' functionality, then that would be just another submit function, not?

eaton’s picture

Status: Needs work » Needs review
StatusFileSize
new18.42 KB

Dries, here's a significant reworking of the patch by chx. I just ran it through some smoke-testing and it appears to be much much cleaner code-wise. hook_form_alter functions now attach their additional handlers *to the buttons themselves* rather than a global #submit operation.

More testing needed, but the technique seems much more consistent and much less kludgy than my above patch. Thoughts?

chx’s picture

StatusFileSize
new18.38 KB

Code style fix.

dries’s picture

I like. Pretty much exactly what I had in mind. :)
(Not tested, just looked at the code.)

moshe weitzman’s picture

Status: Needs review » Needs work

code looks good ... we are showing a preview upon first visiting the the node/add but not after clicking 'preview'. is reverse of desired behavior.

eaton’s picture

Status: Needs work » Needs review
StatusFileSize
new18.8 KB

Fixed. There was a button-comparison that depended on behaviour that was removed in the $_POST['edit'] patch.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

confirmed that preview works and no regressions.

dries’s picture

Status: Reviewed & tested by the community » Needs work

Patch no longer applies.

The %base string matching/replacing is cruft, imo.

eaton’s picture

StatusFileSize
new18.91 KB

Had some funky issues after the most recent fapi patch. Re-rolled to prevent the offsets and confirmation questions in patch.

chx’s picture

Status: Needs work » Reviewed & tested by the community

%base is hardly cruft. Until now, only the default handler had the possibility to be #base_submit or {$form_id}_submit as needed but now, you can do the same with your own handlers if you really want to. The code is not longer than it was, just moved to the better place.

chx’s picture

StatusFileSize
new9.79 KB

Hmm, I tried not against a fresh HEAD. Rerolled.

drumm’s picture

Status: Reviewed & tested by the community » Needs review

Why not require every callback to start with %base_ or even %base_submit_. This would enforce good code (namespace your forms) and remove the need to think about that concept.

chx’s picture

Well, currently we are using module namespacing. So if the module is called mymodule_foo_form and bazmodule wants to add a submit handler that will called bazmodule_something_submit. If we mandate a %base start, then it'll be something like mymodule_foo_form_bazmodule_submit in bazmodule and I do not find this a particularly good idea.

drumm’s picture

How often do we actually want to do that?

RobRoy’s picture

Version: x.y.z » 6.x-dev
StatusFileSize
new9.98 KB

Re-rolled for HEAD. I like the idea of using separate submit callbacks. Will try to test this out a bit more later. Assuming this is 6.x-dev material as well.

ultraBoy’s picture

This seems important for me- one form with different buttons: that's obvious - one button does one thing, another does another thing.

eaton’s picture

StatusFileSize
new10.03 KB

Updated for head. This is definitely a good candidate for 6, though we'll want to revisit the 'how this happens' discussion.

To recap, why is this useful?

Currently, we get one overridable callback -- submit -- for buttons. Previewing is tricky in part because it is a button click that executes *no* submit callback. Other buttons (like 'delete' and 'add more fields') all have to be overloaded in the 'submit' function.

This makes it far easier and far cleaner (from a module developer's perspective) to add many buttons that do different things. Just give each one a different callback, and implement a unique function for each one.

dries’s picture

I fully support this patch except that:

1. the node_submit_early stuff does not belong in this patch. It's cruft.
2. 'preview' and 'reset to defaults' do not have their own callbacks?
3. the %base handling is a bit of a hack, IMO.

Also, would it make sense to enforce a callback for each button? Right now, it looks like we're just adding another way of doing things rather than enforcing one way. Maybe it would be a good idea not to show buttons that lack a callabck?

eaton’s picture

2. 'preview' and 'reset to defaults' do not have their own callbacks?
3. the %base handling is a bit of a hack, IMO.

Also, would it make sense to enforce a callback for each button? Right now, it looks like we're just adding another way of doing things rather than enforcing one way. Maybe it would be a good idea not to show buttons that lack a callabck?

Agreed -- this patch was originally conceived of near the tail end of 5.0's cycle, so there was an attempt to keep it as low-impact as possible. The changes you mention will probably clean things up quite a bit. We can take a look at them for the next roll of the patch.

chx’s picture

The %base was criticized before but it is not too different from the code we already have and I do not see a better solution. Please give me a better solution and it will be coded.

Of course, preview and reset buttons need their own callback.

eaton’s picture

Also, would it make sense to enforce a callback for each button? Right now, it looks like we're just adding another way of doing things rather than enforcing one way.

After a lot of thought, I think this might actually be the best approach. Or, at the very least, the only approach that wouldn't involve using #base as a wildcard character.

The downside would be that EVERY form submit button in core and contrib would need to add '#callback' = array('my_form_submit' => array());. People would probably drift towards using less explicit function names than form_id_submit().

The upsides would be some less complex processing code in areas of FormAPI that deal with callbacks, and a more explicit and readable connection between 'a button' and 'what happens when that button gets clicked' for those ramping up on the API. I think it would be a net gain, and I'll at least roll a version that works that way to see.

I don't, though, think we should hide buttons WITHOUT callbacks; for now, they serve to refresh a form, submitting it to itself, and there are valid cases where that would be useful. Those buttons, like #button elements today, would simply not fire off any dedicated code.

dries’s picture

Eaton: after a lot of thought from my end, I agree that it makes sense to add a callback to every method. The more I think about, the more I like it. It has a very easy "mind model" so it is actually very simple to understand and work with. I think we should explore this some more. :-)

eaton’s picture

StatusFileSize
new51.99 KB

Attached is a patch that converts all of core to the 'callbacks required' system discussed above. I've done some rudimentary testing, but want to get it in front of other eyes for testing.

I think there's some value in looking at the same approach for validation -- we have a fair chunk of code that's dedicated to 'defaulting' these handlers, AND all of the funky '#base' code is made unnecessary if we make these things explicit. That's a separate issue, though.

here are a couple areas of the system that concerned me, because they're in less-cleanly-formapi'd portions of Drupal:

username/hostname mask filtering
system confirmation forms (this in particular, I think I broke. working more on it after I post this.)
poll voting
book orphan editing page
advanced node search

Testing in those areas is doubly helpful.

eaton’s picture

StatusFileSize
new51.63 KB

Re-rolled against the current HEAD. Confirm forms still broken.

webchick’s picture

sub scribe ing

AmrMostafa’s picture

subscribing

eaton’s picture

Status: Needs review » Fixed

Part of FAPI 3 in Drupal 6.

Anonymous’s picture

Status: Fixed » Closed (fixed)
rafiq7s’s picture

Version: 6.x-dev » 5.1
Component: forms system » other
Assigned: eaton » rafiq7s
Status: Closed (fixed) » Postponed (maintainer needs more info)
eaton’s picture

Version: 5.1 » 6.x-dev
Assigned: rafiq7s » Unassigned
Status: Postponed (maintainer needs more info) » Closed (fixed)

This issue was a new feature for Drupal 6, and won't be backported to Drupal 5.