Hi, I've seen people complaining about this in old threads, but it seems they've been after something else in the end...
So, this is what I have:
1) A clean installation of Drupal 6.19, no modules added or enabled (except defaults) but one:
2) The one module is my own and über-simple. It's called mymodule, has a plain .info file and a .module file that contains:
function mymodule_form_alter(&$form, $form_state, $form_id) {
static $i = 0;
$i++;
drupal_set_message("Now at $form_id, static counter is $i");
}
As you can see it gives a message on hook_form_alter (for any form).
When I visit "user/1/edit" I see the message as expected.
But when I submit changes (or just press "Save") i get it twice. Like this:
* Now at user_profile_form, static counter is 1
* The changes have been saved.
* Now at user_profile_form, static counter is 1
Can anyone tell me why? Why does hook_form_alter get called on submit (before render)?
And if this is normal, how can I detect I'm being called on render and not on submit?
So, lets get to what difficulties it brings. Say you want to tell (drupal_set_message), that the name "XXX" is forbidden if he/she sets his/her name to XXX:
function mymodule_form_alter(&$form, $form_state, $form_id) {
global $user;
drupal_set_message("Your name is $user->name".(($user->name == 'XXX') ? " and that's forbidden!" : ""));
}
You set your name to XXX and get this message. So you set it back to YYY and you get:
Your name is XXX and that's forbidden!
The changes have been saved.
Your name is YYYSo, what now? Thanks community!
Comments
I see that the $form_state
I see that the $form_state is filled on submission and empty on render. I can use that, but I still would like the answer to Why is hook_form_alter called on submission.
I don't have the answer as to
I don't have the answer as to why it's being called twice, but the only thing you are supposed to be doing in hook_form_alter() is altering the $form array, so it generally doesn't matter if it's called multiple times, as the each subsequent time it is called will just replace the same $form array.
You are probably putting your message in the wrong spot, but not knowing what you are trying to do, I can't really give advice on where to put it.
Contact me to contract me for D7 -> D10/11 migrations.
.
Try printing $form_id in hook_form_alter. Hook_form_alter gets called for every form on the page. If you got, say, a search box and the form you're using, the hook'll get called twice (once for the search box, once for your own form). If it shows two different form IDs, you'll know to check it. If it's the same form ID twice, we'll have to keep on looking for the reason.
$form_state lost on form rebuilding :(
Is there any way that $form_state be propagated on to the second call to hook_form_alter? I'm trying to add a checkbox to an ubercart page that's persistent when "Update Cart" is clicked. $form_state has the correct data the first time it is called, but the data is lost when the page is re-rendered. I'd like to be able to pull the data from $form_state and use it to alter the form values on refresh.
I've heard that $_POST is lost when the page is redirected, but this instance, there's no redirect, it takes you back to the same page (and I've checked that there's no actual redirect to the same page... #redirect is left empty)
I think I'm going to attempt to accomplish what I wanted to with a submit button rather than a checkbox, so that I don't have to worry about the page refreshing, but it would be good to understand what I'm missing here.
the form is being rebuilt
the form is being rebuilt after submission, so the form alter is called twice.
if you want to perform user validation, have a look at hook_user, or if it is a different context, attach a validation handler, and check the username there
Lee Rowlands
Same in Drupal 7
Same behaviour in Druapl 7.
I do not understand the answer provided by the last comment.
Does anyone have a clearer explanation as to why profile submission is called twice?
The order of processing in
The order of processing in form handling can be a bit bewildering but it's surely not really a major issue, is it? As long as you use the form_alter hook in the recommended manner form processing will work as designed. And the actual submission isn't happening twice, just the building of the form.
Yes, it's a major issue if
Yes, it's a major issue if you are trying to send data to other service who get that duplicate.
That's why your requests to
That's why your requests to external services should be in the submit function, which will only ever be called once.
Contact me to contract me for D7 -> D10/11 migrations.
It will get called twice if
It will get called twice if you got an AJAX form and you mess a few things up with drupal_get_form and drupal_render in the AJAX submit callback. I still haven't figured out why it submits the form twice in that case, but it does.
You don't usually need to
You don't usually need to render anything in the AJAX callback.
Contact me to contract me for D7 -> D10/11 migrations.
You need to reload the form,
You need to reload the form, or create a listing above it. But you're right that you shouldn't use the drupal_get_form + drupal_render combo in an AJAX callback. I've long since stopped hoping that everybody'd do things the way they're supposed to be done, though. So there will be people out there who use that combo (just like I did after seeing what troubles it gave and finding another way as a result). As a result of that, their forms will submit twice. That's why in some cases (which aren't clean, as-it-should-be-done cases), a form actually will submit twice, with all the problems that come with that, like sending a duplicate to external services.
Hei raf, can you provide us
Hei raf, can you provide us with the alternative solution you found? i am not using drupal_get_form nor drupal_render but am still facing the same problem. I do fetch a view in the ajax callback and i use drupal_rebuild_form along with $form_state['rebuild'] = TRUE in a custom submit callback for otherwise it doesnt update the form fields.
What I did, is I simply
What I did, is I simply didn't touch the form. No drupal_render_form, but also no rebuild = TRUE, as that creates messes as well. My solution was changing the wrapper I defined to contain only the list that had to be updated (in your case the view). The form is outside of the wrapper. That way, the form stays fine (no double submitting or errors in the style of "Someone else already created that node" or other weird stuff), while your list does get updated.
Module and Theme having same name
Note that when your custom module and your theme have the same name, hook_form_FORM_ID_alter will be called twice. I have no idea why, I just saw it mentioned on drupal stack exchange with no explanation. And it worked for me (d7). Hope that helps!
Hawkeye Tenderwolf
a Senior Developer
at Lullabot
Never give a custom module
Never give a custom module and theme the same name. It leads to all sorts of problems, some much worse than this.
If you have custom theme and
If you have custom theme and module with the same name, form_alter will be called twice.
You're a life saver!
Thanks!