If you want to avoid the ctools dependency but want to avoid the pitfalls of inline js-ing...
In your submit handler
if (current_path() == 'system/ajax') {
// This was an ajax submission.
// Cause Drupal to rebuild the form
$form_state['rebuild'] = TRUE;
// Special flag, call it what you want.
$form_state['ready_to_go'] = TRUE;
}
Then in your build form function do something like
if (!empty($form_state['ready_to_go'])) {
// Add js to autosubmit, stored in an external js file.
$form['#attached']['js'][] = drupal_get_path('module', 'mymod')
. '/my-bit-of-js.js';
}
Then your my-bit-of-js.js
file finds the form and submits it immediately.
What this will do
Your form is ajax enabled. Validation errors are returned, as you wish. Once there are no validation errors, the form is submitted, but is actually returned rebuilt identical, except for the inclusion of your auto-submit-my-form js, which submits the form through a non-ajax submission, and from there you can issue whatever redirect you want.
While you could have your js do the redirect (as in your inline example), the benefit of doing the full non-ajax submission is that you can use PHP to determine where to redirect to, since the external js file is not going to be based on any of your form values, which the redirect might need to be. I know in this specific case you just want to reload. So just treat all this as a helpfully intended jus' sayin' :-)
Aside: Multi-step form ajax except last page
I came upon this when I had a multi-page form that I wanted to be ajax until the final page (because I wanted a redirect on final submission). The way I'd done this was that I'd built the last page of the form without the #ajax
on the submit elements. This resulted in quirky behaviour though because Drupal could no longer call the ajax callback that would return the last page of the form because it looks to the rebuilt form to find the callback(!). The solution I found was to hide ('#type' => 'hidden'
) the "next" button and leave it's #ajax
stuff in place, but then provide a different submit button without the #ajax
stuff (which needed a different #name
).