Problem/Motivation

When a node form fails validation (i.e. a required field is not filled) and displays the node form again.. the hook_form_alter is not being executed, so any alterations done by any module on a node form are not executed.

This is no longer true in Drupal 8. So the issue affects Drupal 7 and 6 (though D6 is no longer supported.)

Proposed resolution

TBD

Remaining tasks

Provide steps to reproduce

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

grendzy’s picture

Status: Active » Postponed (maintainer needs more info)

I couldn't reproduce this issues with Drupal 6 HEAD. I tested this using path module (the "URL path settings" fieldset is added via hook_form_alter).

Is it by chance a multi-part form? There is some weirdness going on there, see #302240: button broken due to fix various problems when using form storage

joelstein’s picture

I'm having the same problem. My "custom" module's hook_form_alter is simply not getting executed when re-presenting the form after failed form validation.

Dave Reid’s picture

I can't duplicate this either with base functionality. Make sure nothing is altering the form to be cached as that might cause this to be skipped after validation.

slashwalk’s picture

Yes i can confirm this happens to me with a custom module, i make field alterations on the module. I went with another approach i decided to create a new cck widget for the feature i wanted.

ExTexan’s picture

Plus 1 on this... I'm doing hook_form_alter on the user_register form. In it, I drupal_set_title('Register) - but noticed that it reverts back to "User Account" if errors are encountered during validation. I added some dpm(xxxx) diagnostic displays, but they don't show after validation either.

bmdhussain’s picture

I got the same issue in ipaper node form. I have added one validation method in the form to validate file attachments. It's not triggering the validation. Any clues?..

mrfelton’s picture

Same problem for me. Using hook_form_alter on a node add form. When validation of the form fails, the form_alter is not called when the form is rebuilt.

mrfelton’s picture

Version: 6.15 » 6.16

Actually, just noticed that mymodule_form_alter() does get called after failed validation. But the more specific, mymodule_form_contet_type_node_form_alter() does not.

EDIT: Actually, that was only because I had the drupal for firebug module installed. After uninstalling that module, form_alter is not called after a validation failure at all.

mrfelton’s picture

Actually, I take it all back, form_ater is apparently not supposed to get called twice as it is cached. I got around this by using #after_build to add js to my page (which is what I was trying to do in form_alter) - see http://www.appnovation.com/drupaladdjs-and-drupaladdcss-hookformalter-an...

xandeadx’s picture

subscribed

Jaypan’s picture

Using #after_build worked for me too. I did it like this:

function hook_form_alter(&$form, &$form_state, $form_id)
{
  if($form_id == 'node_form') // this needs to be the actual ID of the form
  {
    // hook alter stuff
    $form['#after_build'][] = 'mymodule_after_build';
  }
}

function mymodule_after_build($form, $form_state)
{
  // First I re-attach the original submit handler to the form
  $form['buttons']['submit']['#submit'] = array('node_form_submit');
  // Then I return the form
  return $form;
}

This way the submit handler is always attached to the form.

sgtpep’s picture

subscribed

sgtpep’s picture

Here the patch that works for me.

grendzy’s picture

Status: Postponed (maintainer needs more info) » Closed (works as designed)

See #9 regarding #after_build.

sgtpep’s picture

Few Drupal modules uses hook_form_alter for form modification and requires calling of this hook even if validation fails. Some of known to me modules with this issue: markitup, twitter-3.x. So this change of Drupal core is not backward compatible.

grendzy’s picture

If this is an issue of backwards compatibility, can you help locate the commit that introduced the change?

sgtpep’s picture

No, I was wrong, I couldn't find this change. But this behavior of hook_form_alter is strange and unexpected in my opinion.

grzegorz.bartman’s picture

subscribing

kenorb’s picture

Are you using some kind of $form_state['redirect']?
Maybe that's the reason? It's redirected before the hook_form_alter is called.

aacraig’s picture

I can confirm the same behavior, and I'm not doing any redirection.

Alan D.’s picture

Version: 6.16 » 6.x-dev
Priority: Critical » Major
Status: Closed (works as designed) » Closed (won't fix)

This should be either a "won't fix" or an "active" bug, depending on what the powers to be decide on. AKA is is a fairly big developer wtf in the rare use case where is shows itself.

Considering that it is an api change, I've tagged as "won't fix".

Good news is that it appears fixed in Drupal 7.

arosboro’s picture

Doesn't look fixed in D7 to me, I had to resort to using #after_build which gets called every time the form loads.

Alan D.’s picture

@arosboro
I ran some tests at the time of comment #22 and these failed to get called on Drupal 6, but were called on Drupal 7. So, was the alter() in the main *.module file or via an include somewhere? If in an include, try including the alter hook within the main module file and if that fails, I think that this may need to be reopened!

arosboro’s picture

The alter is in my main module. I'm using hook_form_FORM_ID_alter(), but I changed it to hook_form_alter() with a case for my form_id, and the dpm statement I added still did not appear on the validation error page.

arosboro’s picture

@Alan D

Actually, I just realized this was on Drupal 7.0. I've upgraded to 7.12 and the hook is evaluated as expected. This issue can remain closed.

arosboro’s picture

@Alan D

I need to take back my response in #26. It seems as if hook_form_alter was called on the validation error page after I first installed 7.12, but after using the form for a while it reverted back to using a cached form without calling hook_form_alter.

Alan D.’s picture

Sounds more like a panel caching issue from that description. Can you tell us the steps to replicate or at least what form?

manuelBS’s picture

I got the same problem (I use panels and display suite, too). I solved the problem by setting

function my_module_form_alter(&$form, &$form_state, $form_id) {

  if ($form_id == 'my_form') {
    $form_state['no_cache'] = TRUE;

    ......
  }
}

With disabled form cache hook_form_alter is called even after form validation.

crevillo’s picture

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

this indeed fix the the first part. hook_validate seems to be executed again, but i've lost my ajax functionality.

jide’s picture

You could try using #after_build :

function my_module_form_alter(&$form, &$form_state, $form_id) {
  $form['#after_build'][] = 'my_module_form_alter_after_build';
}

function my_module_form_alter_after_build($form, &$form_state) {
  ...
}
Alan D.’s picture

On a clean install, can someone give the minimal steps to replicate that do not involve adding panels, etc. A simple module may be needed to demonstrate the issue.

If you can, re-open. There is enough activity here to suggest that it is an active bug, but I have tried unsuccessfully to mimic on Drupal 7 (and I do not have Drupal 8 running).

kenorb’s picture

Status: Closed (won't fix) » Closed (cannot reproduce)

Maybe it'll be better to report it against Panels module.
It'd be good, if somebody can dump the whole $form and $form_state, which external callbacks are defined (in form_alter and in validation hook).

Damien Tournoud’s picture

Status: Closed (cannot reproduce) » Closed (works as designed)

This is by design: hook_form_alter() is only called when the form is actually rebuilt. If you want to run something every time the form is rendered, add a #pre_render callback to the top-level $form.

Jaypan’s picture

Can you add that in hook_form_alter()?

Alan D.’s picture

yes. Another wtf though, this must be in the defined path for Drupal 7 at least.

zach.bimson’s picture

You are going to have the same problem with this as you are with putting your alter code in hook_form_alter()...
If the prebuild is called within that hook its not going to get called when its validated.

zach.bimson’s picture

Does anyone have any other suggestions?

Damien Tournoud’s picture

You are going to have the same problem with this as you are with putting your alter code in hook_form_alter()...
If the prebuild is called within that hook its not going to get called when its validated.

Not sure what you are talking about. If you want to do something everytime the form is rendered:

  • Register a #pre_render callback in a hook_form_alter()
  • Do your stuff in the #pre_render

When the form is loaded from the cache, it would already be altered, so your #pre_render will already be there, and will be executed when the form is rendered.

zach.bimson’s picture

I'm talking about the fact that form_alter is only called once...
Even if i turn page caching on the node form im altering does not keep the changes made in in my custom function.

The pre_render is declared in form alter so will not be called/ defined again once the validation is called.
I know drupal core should cache it but it doesnt seem to be.

Im also now getting this error

Notice: Undefined index: #build_id in drupal_process_form() (line 941

Code sample:

function mymod_form_form_alter(&$form, &$form_state, $form_id) {
  $form['#after_build'][] = 'mymod_form_form_alter_after_build';
}

function mymod_form_form_alter_after_build($form, &$form_state) {
   
}
zach.bimson’s picture

Sorry to be persistent but does anyone have any suggestions as to how i can get this to work?
My form alter elements are required after validation.

Thanks in advanced.

Zach

Jaypan’s picture

#pre_render is not a valid option, as there is no access to the $form_state in #pre_render.

Jaypan’s picture

Status: Closed (works as designed) » Active
pingers’s picture

This cannot be reproduced in a clean D7 HEAD install.

Using a module with the following...

function meh_form_alter(&$form, &$form_state, $form_id) {
  $form['title']['#description'] = 'a';
}

function meh_form_node_form_alter(&$form, &$form_state, $form_id) {
  $form['title']['#description'] .= 'b';
}

function meh_form_page_node_form_alter(&$form, &$form_state, $form_id) {
  $form['title']['#description'] .= 'c';
}

I see abc printed under the title field for page nodes every time.
E.g. Fill in 123 in the body field and hit save, title is required, validation fails, test string "abc" is present under Title field, indicating that hook_form_alter (in each incarnation) is taking effect. Using a debugger, I can confidently say that each and every one of those hooks fired, validation failure or not.

Soo... what's the deal? Sounds like custom code breakage to me. Really going to need more info about what is broken and how to break it, or this is closed - cannot reproduce.

Alan D.’s picture

Status: Active » Closed (works as designed)

@Jaypan You can use an afterbuild instead then. It only has context to the element and form state. i.e.

  if (isset($element['#after_build']) && !isset($element['#after_build_done'])) {
    foreach ($element['#after_build'] as $function) {
      $element = $function($element, $form_state);
    }
  }
dahousecat’s picture

The solution in post #11 works for me - thanks for the code - was getting a bit worried for a second there!

EDIT: Using the after_build callback introduced some new errors for me (can't add new value for fields that allow multiple values) so I've used pre_render instead and now is all working great.

fire-wolf’s picture

Code sample from #40 works as expected while there is no drupal_add_js in code I move to _after_build. I have to add javascript and after validation errors there is something strange - submit button doesn't work. Tried to put drupal_add_js into hook_init() - the same. Tried to load javascript with .info directives - the same. I did a little changes to submit button - changed only title and position in form. Can anyone recommend something?

fire-wolf’s picture

Okay, #pre_render option works too. But it have some limitations. If I define button in _form_alter() using:
$form['buttons']['some-container']['next'] = array(... button parameters...) then I can access this button with javascript with commands like $("#edit-next").click(...), but if I define the same button in #pre_render specified function, then the same button doesn't have id="edit-next". It doesn't have any id. So the question is what to do? Do I need to rebuild form? #pre_render function doesn't receive $form_state and therefore I cannot specify $form_state['rebuild']=TRUE. I tried to rebuild in #after_build function, but then submit button looses its functionality - form after submission returns in state edit with no errors/messages. I'm stuck. If I don't use javascript, then all seems to be okay, but I need javascript there to move buttons at right place.

If it "works as designed" then I call for designer!

rooby’s picture

One thing to note about #after_build is that it gets run before you know whther or not validation fails, so if you need to distinguish between a form that has been submitted and has failed validation and a form that didn't fail validation you cannot do it there.

illeace’s picture

Related to this discussion, any ajax form elements (like the "Add more items" button) will automatically turn on form caching, which (as pointed out above) will result in form alter functions not being called during validation.

If you're just trying to add some javascript to the form (as I am), the "after_build" workaround mentioned in #31 is a good solution. Keep in mind that the "after_build" callback function needs to return the $form variable, otherwise you're going to end up with an error along the lines of:

Notice: Undefined index: #build_id in drupal_process_form() (line 943 ...

ankur140290’s picture

I don't know how many of you have tried this but the best and simple way to do this disable cache of the required form as mentioned by comment #29.

Alan D.’s picture

"disable cache" and you should see the AJAX calls fail :(

TechNikh’s picture

#11 worked for me

webcat7’s picture

#11 worked for me too

StephenRobinson’s picture

same issue in D7, think it is just the javascript that is missing

Elin Yordanov’s picture

Issue summary: View changes
Status: Closed (works as designed) » Active

None of the proposed solutions are satisfying. Setting no cache the ajax functions not working any more, and #after_build is limiting. I am not agree with that hook_form_alter should not be called "by design" after a failing validation.

rooby’s picture

Yeah, it would be good to be able to handle the case in #49.

acb’s picture

Has anyone come up with a solution for this or does it simply languish?

Alan D.’s picture

Issue tags: +DrupalWTF

Anyone tried to replicate this in Drupal 8.x? This is probably the only version that could potentially get an API change like this in sadly, if it is not too late already....

kristiaanvandeneynde’s picture

I just ran into this as well and I must say this is an extremely annoying 'design decision' to call 'working as intended'.

I could agree that you do not need to call hook_form_alter() again on cached forms and I could even agree that this causes any form-unrelated actions in hook_form_alter to be discarded (drupal_set_title(), drupal_add_css(), ...). After all, we have other means such as #attached for that.

What I simply find weird is that ANY form alterations from hook_form_alter are discarded altogether: extra validation handlers, altered form elements (labels, descriptions, ...). Those are clearly meant to be there every single time the form is loaded, why else would you have a function named hook_form_alter()?

Furthermore, I find the 'solution' to be very ugly: Register a hook_form_alter() to register a mymodule_after_build() for EVERY form you want to alter (I sense a "Yo Dawg" meme lurking around the corner). That's twice the amount of functions for half the amount of developer fun.

TL;DR: What's the point of having a function to alter forms with if it doesn't always work?

acb’s picture

Yes… seems like a catch-22. #pre_render funcitons added in the form_alter also get lost.

arif.stalker.majid’s picture

Any solution to this issue cuz its still happening ...
And all the options stated above
1. setting no cache (ajax file upload breaks)
2. using the after build option

seems to be incomplete in one way or the other

headbank’s picture

Subscribin', for all the good it seems likely to do... This is ludicrous "design".

My own use-case is, I think, fairly simple compared to many of the above: I created, strictly per the D7 API docs, an AJAX-driven form where the values of the first couple of fields influence the contents of the third (a list of radios, built to a default config by the form-builder then regenerated via the #ajax callback on the other fields).

All I'm looking to do is create a sane fallback mode for non-JS users. Based on the above and my own attempts, it appears the best I can do in the event of validation failure is to trigger form_set_error() and tell the user what they did wrong -- I can't actually reset the invalid fields to a sane value.

Never mind adding *_form_alter() functions just for this purpose, why isn't this functionality supported in the validation function itself?

Words fail me.

rooby’s picture

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

Seems like no one has properly looked into whether or not this also affects Drupal 8.

Making this a Drupal 8 issue until it is either fixed in D8 or confirmed that it isn't an issue in D8.

rooby’s picture

@headbank: The form_set_value() function can set form value from the validate function, although it sets it in $form_state['values'] so I'm not sure off the top of my head if that will end up back in your form on a validation error.

headbank’s picture

@rooby, Thanks for the suggestion, I'll look into it; however if all it does is set the $form_state['values'] values then it won't work, because so far I've been changing those manually and I can see that they're not fed back into the form when it's reloaded (I think that $form_state array passed into the validation function is just thrown away if validation has failed).

I should add that I've also added $form_state['rebuild'] = TRUE and it made no difference.

UPDATED TO ADD: From studying this thing of nightmare, it looks like $form_state should be preserved (saved back to the cache for re-rendering) "if cache is set and no_cache is no set and rebuild is not set" (at bottom middle in the chart). I'll try this; if that doesn't pan out it looks like I'll just have to make a multi-step, non-AJAX form instead. Which will be crap for everyone except the handful of people who might not have JS turned on.

UPDATED AGAIN TO ADD: The sanest, hack-free way I can find so far (albeit massively counterintuitive) is to not call form_set_error() in the validation function, but to instead set a custom flag in $form_state['foo'] that causes the submit function to bail and return to the form page (instead of the processing and redirect it performs on successful validation). As I also set $form_state['rebuild'] = TRUE (or maybe this doesn't even matter, I dunno), I can also use $form_state to pass details of the errors back to the form-builder function.

This still strikes me as a ridiculous way of doing things, though, and I'm no closer to being able to rationalise why, when my form is filled in incorrectly, the "Drupal Way" doesn't let me tweak the data in any meaningful way to return it to a sane state from which the user can continue, duly advised of what's wrong. I can either tell them what's wrong (using form_set_error()), or fix it for them (using the submit handler), not both. #DrupalWTF indeed.

Alan D.’s picture

"so I'm not sure off the top of my head if that will end up back in your form on a validation error"

On validation with errors, the changes are lost.

Sadly, you need to hack things here. Possible to check $_POST / $_REQUEST, or start with globals or in the worst case (for the multistep if required) the session.

Note it is possible that the form token is altered between submit attempts, I remember getting caught out once with this, but the details escape me (i.e. $SESSIONS['wtf_drupal_form_cache'][$form_state['values']['token']] = $form_state['values']; failed) .

headbank’s picture

Here is how I make corrections to rebuilt form values when validation has failed in D7. It relies on the undocumented array, $form_state['input'] (these are the values that get loaded back into a rebuilt form).

  1. In your validation handler, if your validation fails, set $form_state['rebuild'] = TRUE but don't issue any calls to form_set_error().
  2. You can arbitrarily add any variables you need to $form_state['fnord'] (or whatever) for access when rebuilding. Here you can also set a flag to tell your submit handler not to process the form.
  3. In your submission function, make your processing logic conditional on whatever flag you set in the last step.
  4. In your form builder function, use whatever information you stored in $form_state['fnord'] to restructure the form as needed.
  5. If you need to alter the user-submitted values, alter them in the $form_state['input'] array (which is basically the $_POST or $_GET array) for inclusion in the rebuilt form.
  6. The effects of form_set_error() can be simulated by using drupal_set_message() for notifications, and highlighting errored fields with $form['myfield']['#attributes']['class'][] = 'error'.

Hope that helps somebody.

marcingy’s picture

Status: Active » Closed (won't fix)

As per https://www.drupal.org/node/671574#comment-6466782 this by design a form is only built 'once'.

kristiaanvandeneynde’s picture

Status: Closed (won't fix) » Active

Respectfully, closing this issue like that is not the way to go. It's even incorrect to state that forms are only built once by design, because they aren't. They're only built once if caching is enabled.

It's plain to see that a lot of people are confused about some parts of their form alter not working consistently. At the very least we should update the documentation of hook_form_alter(), hook_form_FORM_ID_alter() and hook_form_BASE_FORM_ID_alter() to reflect that cached forms will not run their form alter code again.

While it is completely logical to not run the form alter again, we should at the minimum tell people about the available ways to circumvent this behavior: #attached, #after_build and perhaps #pre_render.

rooby’s picture

As per #49 #after_build is not always a viable solution.

ladybug_3777’s picture

I just ran into this problem with some custom javascript I am adding to my form. My custom JS allows me to select an option from a drop down and pre-populate other drop downs on the form based on that first selection. I was using hook_form_node_form_alter for my drupal_add_js() call.

I agree with others that feel confused that the hook is only called once, and not if validation fails. I will need to try out some of the other suggestions (#attached, #after_build, etc).

ladybug_3777’s picture

The after_build path seems to be working for me so far. For those that are new to after-build remember you have to return $form (That messed me up for a few moments!)

Example:

function yourmodulename_form_alter(&$form, $form_state, $form_id) {
  dsm('form alter is being run');
  if($form_id == 'yourformid'){
    //all of your custom code WAS here
    //drupal_add_js('myjavascript.js'); This line isn't run when validation fails. Move it to the after build function
  }
}

function yourmodulename_after_build($form, &$form_state) {
  dsm('after build is being run');
  //all of your custom code moves to here now
  drupal_add_js('myjavascript.js'); //This line now works even after validation fails.
  return $form;
} 

Remember you must have the devel module if you are using dsm(); I added those in there for debugging as an example of when these functions are (and are not) run, they are not required of course

marcingy’s picture

If you use #attached rather than drupal_add_js then you should no need to use yourmodulename_after_build as #attached ensures that all assets are re-added even when the form is rebuilt from cache.

ladybug_3777’s picture

Thanks so much marcingy! That seems to work great! It also seems to be a better solution because my after_build was being called on every ajax call so my javascript settings data was being added twice. I was actually struggling a bit with an array merge issue because of the ajax calls interaction with my JS settings data. #attached seems to solve that completely for me.

*edit* Well I guess technically the js is still re-added on ajax through attached, but the array settings issue went away at least.

AlexZt’s picture

#68 worked for me
The problem was in form_set_error()

I removed this function call with "form_validate"
and remove the option "#required" for all fields.

pratip.ghosh’s picture

#73 was the problem for me. This is really a minute details that needs to be attended carefully.
Thanks

tim.plunkett’s picture

Title: hook_form_alter not called after a form fails validation » Document that hook_form_alter not called after a form fails validation
Priority: Major » Normal
Issue tags: -forms, -hook_form_alter, -validation +Documentation

While it is completely logical to not run the form alter again, we should at the minimum tell people about the available ways to circumvent this behavior: #attached, #after_build and perhaps #pre_render.

+1

i.bajrai’s picture

#74 "#attached" for javascript. drupal_add_js in the form_alter does not work after validation fails.

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.

ann b’s picture

I need to set a default value for a webworm dynamically, i.e. every time the form is rendered. I tried the following and none of them worked:

  1. Changed the default value directly in hook_form_alter
  2. Added a pre_render callback on the form itself in hook_form_alter, and changed the default value in the callback function.
  3. Added a pre_render callback on the field in hook_form_alter, and changed the default value in the callback function.
  4. Added an after-build callback on the form in hook_form_alter, and changed the default value in the callback function.

I know this issue is about form validation, but there was some discussion about hook_form_alter being cached and not executed every time the form is rendered. I understand this is by design. The only thing that has worked so far is to add drupal_page_is_cacheable(FALSE); in hook_form_alter after checking the form id. Without this function call, I saw the page getting cached in the cache_page table as a blob. So all page requests contain the default value calculated during the first request after clearing the cache. I still need to test this tomorrow.

Drupal 7.51
Using Drupal database caching system.

tim.plunkett’s picture

This is a D8 issue, drupal_page_is_cacheable() does not exist anymore.

Alan D.’s picture

rooby commented December 9, 2014 at 7:10am
Version: 7.x-dev » 8.0.x-dev
Seems like no one has properly looked into whether or not this also affects Drupal 8.

Making this a Drupal 8 issue until it is either fixed in D8 or confirmed that it isn't an issue in D8.

No one has confirmed this is a D8 issue since 2014!

tim.plunkett’s picture

Version: 8.2.x-dev » 8.4.x-dev
Issue summary: View changes
Issue tags: +Needs issue summary update

Then that is the first step.

joseph.olstad’s picture

subscribing,
Scenario: Drupal 7.54 (patched with several rtbc patches), wrote a custom module for adding javascript on node edit form after validation and before validation.

Background:
I'm adding some validation to prompt a confirm popup when the publish checkbox is checked. I am able to add my javascript to the form for all the node types , however only some of my node types are getting my javascript after a form validation failure (for instance an empty title field where title field is 'required').

progress:
while using #attached helped for me for some of my node types to load my javascript after validation failure, I still have at least one node type (haven't tested all of them yet) that refuses to load my javascript after a validation failure. Suspect perhaps the difference between the node types is one has revisions enabled, the other one doesn't have revisions. The node edit form that has no revisions loads my javascript ok before and after validation (success or failure) , however the one that HAS revisions only loads my javascript prior to any validation failure ; and upon failure, my javascript is not loaded so my custom confirmation box doesn't show up.

Here's the add js

/*
 * Alter the node edit form for all node types to fit requirements for Add javascript popup CONFIRM on publish node.
 */
function mymodule_form_alter($form, $form_state, $form_id) {
  //  Known issue, after fail validate article nodes refuse to load js, however video nodes are ok either way.
  if (isset($form['#node_edit_form'])) {
    if ($form['#node_edit_form'] == 1) {
      $path = drupal_get_path('module', 'mymodule');
      drupal_add_css($path . '/css/confirm-publish.css');
      drupal_add_js($path . '/js/confirm-node-edit.js');
      mymodule_attach_js_css($form, $path . '/js/confirm-node-edit.js', $path . '/css/confirm-node-edit.css');
      $form['#after_build'][] = 'mymodule_after_build';
      watchdog('my_debug', '<pre>@print_r</pre>', array('@print_r' => print_r( $form, TRUE)));
    }
  }
}

/**
 * After build form callback.
 */
function mymodule_after_build($form, &$form_state) {
  $path = drupal_get_path('module', 'mymodule');
  mymodule_attach_js_css($form, $path . '/js/confirm-node-edit.js', $path . '/css/confirm-publish.css');
  return $form;
}

function mymodule_attach_js_css(&$form, $js, $css) {
  if (!isset($form['#attached']['js'])) {
    $form['#attached']['js'] = array();
  }
  $form['#attached']['js'][$js] = array(
    'type' => 'file',
    'weight' => -10,
  );
  // Add CSS.
  if (!isset($form['#attached']['css'])) {
    $form['#attached']['css'] = array();
  }
  $form['#attached']['css'][$css] = array(
    'type' => 'file',
    'weight' => 10,
  );
}

Here's my javascript code:

(function ($) {
  Drupal.behaviors.MYAdminEditNode = {
    attach: function (context, settings) {
      MYAdminEditNode.initialize();
    }
  };

  MYAdminEditNode = {
    initialized: false,    // Flag to indicate one-time initialization
    confirmed: false,
    noStates: false,
    hasStates: false,
    /**
     * Initialization (one time)
     */
    initialize: function () {
      if (MYAdminEditNode.initialized) {
        return;
      }
      var noStates = $('input#edit-status').length;
      if (noStates) {
        MYAdminEditNode.noStates = true;
        //alert('has checkbox');
      }
      var hasStates = $('#edit-workbench-moderation-state-new option:selected').length;
      if (hasStates) {
        MYAdminEditNode.hasStates = true;
        //alert('has dropdown');
      }
      $('#edit-submit').mousedown(function() {
        if (MYAdminEditNode.hasStates) {
          if ($('#edit-workbench-moderation-state-new option:selected').val() == 'published' ) {
            MYAdminEditNode.confirmPublish();
            if (MYAdminEditNode.confirmed) {
              $('#edit-submit').click();
              MYAdminEditNode.confirmed = false;
            }
          } else {
            MYAdminEditNode.confirmed = true;
          }
        }
        if (MYAdminEditNode.noStates) {
          if ($('input#edit-status:checked').length) {
            MYAdminEditNode.confirmPublish();
            if (MYAdminEditNode.confirmed) {
              $('#edit-submit').click();
              MYAdminEditNode.confirmed = false;
            }
          } else {
            MYAdminEditNode.confirmed = true;
          }
        }
      });
      //prevent publishers from publishing without a confirmation.  When MYAdminEditNode.confirmed is false, abort the click event by returning false.
      $('#edit-submit').click(function() {
        return MYAdminEditNode.confirmed ? true : false;
      });

      MYAdminEditNode.initialized = true;
    },

    /**
     * confirmPublish , force the user to confirm this action, because if they publish, it goes live immediately.
     */
    confirmPublish: function() {
      var title = $('#edit-title').val();
      if (typeof title == 'undefined') {
        title = $('#edit-title-field').find('input.form-text').val();
      }
      var confirmMessage = Drupal.t('Are you sure you want to publish:') + "\n\n" + title + "\n\n?";
      MYAdminEditNode.confirmed = confirm(confirmMessage);
    },

    /**
     * Some other function
     */
    someOtherFunction: function() {
      alert('test other function');
    }
  };
})(jQuery);

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.

i.bajrai’s picture

I can confirm this is still happening in Drupal 8.

I am trying to add a custom form element to the page if validation fails. More specifically a checkbox that would stop the validation from failing if checked.

I cannot access anything useful in #afterbuild and the hook_form_alter is not called at all.

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.

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.

JohnAlbin’s picture

Version: 9.2.x-dev » 7.x-dev
Issue summary: View changes
Issue tags: -Needs issue summary update

> I can confirm this is still happening in Drupal 8.

That's weird. I just tried this on Drupal 8.9.9-dev and the form_alter is called just fine when form validation fails.

Steps to reproduce:

  1. Installed software: Drupal 8.9.9-dev, xdebug and contrib module Formdazzle with formdazzle_form_alter()
  2. Go to a node edit form and delete the text in the title field. Open the web inspector and delete the required attribute on the title input field so it doesn't do client-side validation.
  3. Turn on xdebug, set a breakpoint on formdazzle_form_alter(), and submit the form.
  4. Xdebug stops the execution on formdazzle_form_alter(). Hit the play button to let PHP continue executing.
  5. The node edit form returns to the browser with a validation error saying "1 error has been found: Title".

I'm moving this back to the Drupal 7 issue queue.

Berdir’s picture

Drupal 8 is different because it only caches forms after the first ajax submission. The first ajax or regular submission rebuilds the form the first time, only repeated ajax calls validate the form against the cached version. Try to repeat your experiment by repeatedly using something like an image field/add more button.