I have a Drupal module page where I am populating a form with a drop-down that contains a list of available parts of a set of files that the user can upload. Once the user uploads a file of a certain type, it removes that option from the list, and when all the available files are uploaded the form will not be rendered.
The problem is that Drupal is drawing the form before it carries out the submit action, so it appears to the user that the operation didn't work until they reload the page.
What is the common way to deal with this? Setting form_state['redirect'] to go to the page doesn't seem to work.
You modify your form so that it saves some information on the state of the form. Then you add a new case to the beginning of the submit function that returns immediately if you're not done uploading all the files, and it will redraw the form.
function modulename_uploader_form(&$form_stuff=null) {
//the function that sets your form array
$stuff = (isset($form_stuff['values'])) ?
$form_stuff['storage']['done_uploading'] :
false; //if values isnt set, this is the first visit.
$form_stuff['storage']['done_uploading'] = done_uploading();
.... the rest of your form creation function.
function modulename_uploader_submit($form, &$form_stuff) {
if($form_stuff['storage']['done_uploading']) {
return;
}
... rest of the function
make sure to unset the storage variable when you're done processing the form. You can also google multi page forms in drupal.
Setting $form_state['redirect'] in your submit handler will just cause the form to reload, fresh, without the old data. It's a way of clearing out the form so that old values don't hang around as defaults.
You probably want to use $form_state['rebuild'], which gives your form-building functions an opportunity to rebuild the form's actual structure, adding more fields or removing options from other fields after the form submit handlers run.
This blog post has a rough tutorial on doing multiple-stage forms in D6, and the Drupal 5 to 6 upgrade docs on Drupal.org contain a useful overview of how $form_state works and what its various flags are for.
The problem is that Drupal is drawing the form before it carries out the submit action, so it appears to the user that the operation didn't work until they reload the page.
I cannot believe it. Are sure about that?
Related
I am making a simple form with a submit button inside of it. In order to do this I used a shortcode which returns the form. I would like to prevent the user from submitting the form multiple times. However, the answers I have found tend to rely on disabling the button using javascript in some way. If I understand correctly this has two problems.
If the user stops the page, the button will be permanently disabled.
The client code can be changed manually by the user to send multiple requests even if the button is disabled.
I was wondering if there is some way to handle this on the server side in php?
The main problem I am having is that the shortcode needs to return something. It is possible to store a unique code using a nonce, the database or other methods to uniquely identify the submission. However, I can't find a way to cancel execution before the shortcode starts.
Also, when I was trying things I found that if I sleep the function so I can spam the submit button, only the final shortcode submission is returned. So I can't simply return a working copy of the form either.
It seems this would be a standard problem, so am I missing something?
I currently have two PHP files set up, one that functions as the form and the other that functions as the processor of the information provided. They are linked together like so:
<form action="processing.php" method="POST" enctype="multipart/form-data">
When I hit submit, the page switches to the 'processing.php' file. I recently implemented required fields that users must enter, but they cannot see this warning because the page switches. I am testing this in WAMP.
I think a solution may be to include the processing script in the same file as the actual form, but the script is pretty long and I'd really like it to stay in two separate files for readability.
Is there a way that I can prevent the page from switching to the page indicated in the action tag?
The HTTP POST from a form goes to whatever form action you set. If you want logic applied that's in a different file, you need to restructure things so that your logic is in processing.php, or you need to change the form action.
If you want to prevent page refresh all together, you need to use ajax.
If you only want to prevent the page switch if the required fields aren't properly filled, you need to create an onSubmit javascript call, then return false if field validation fails.
I'm using Drupal 7 and HAVE to use the Form Maker (https://drupal.org/project/drupal-form) module. Since it's not a normal form, I don't know how to do something like hooking as Drupal form submission Q/A explains for normal forms.
The available options for "action after submission" for those in-database forms are:
Stay on form.
Link to an article.
Display custom text.
Redirect to an URL.
Is there any way I can handle the form submission? e.g.: Is there a way to reference the form state for the submitted form in the url I specify if using (e.g.) option 4? (or whatever mechanism exists to recover that data by knowing+referencing the submitted record).
BTW I'm a total drupal n00b, and couldnt Find TFM to R (so I can follow the RTM principle) about that special issue in the Form Maker doc.
It looks like this module still uses the form API, so you should just be able to use hook_form_alter() to modify these forms. I'm sure there's some kind of naming convention for the IDs of these forms, which will allow you to apply changes exclusively to form maker forms.
If you need to customize the handling of form submissions, you can include your own submit handler by using the #submit form attribute. Note: the example in the link adds the submit handler to a field in the form, but in most cases I add the submit handler to the form array itself. (i.e. $form['#submit'] = array("submit_callback"))
Edit in response to comments
You do not need to reference a form_id when invoking hook_form_alter(). Instead, you can invoke it globally, which will cause drupal to call your hook on every form. As you can see from the documentation link I provided, the $form_id is passed to the function, and you can use that to conditionally modify the form. Please look at the comments on the documentation page for usage examples.
Unless these forms are being embedded using a third party service, if this module is actually legitimate it will be hooking its forms through the form API. Implement hook_form_alter(), and print off the form_id's that are passed to the function. Go to a page that has one of this forms on it, and see what gets printed.
(Also, [form_id]_form_alter() is not the correct syntax for invoking this hook on specific forms. Should be hook_form_[form_id]_alter(), where hook is your module name.)
On any given page (It's used site-wide for different purposes) I'd like to call a function getMyForm() or something similar and this would render a several step selection process for a product. We only have this one product but it is quite a complex selection process.
If I wanted to implement this on one page only it would be fairly simple... but I'd like this selection process to be available on different pages, and it seems silly for me to recreate the form for each page used when it's only really the outcome after the selection process that will change for each.
How would I go about achieving this:
Should I have the form on it's own page anyway then link to it at the beginning of the selection process and redirect to the appropriate page after selection depending on the page the user first came from?
Use a service container or similar to render the form on the specific page, then use session attributes/variables to track which step the user is currently on, and refresh the current page after each selection.
Something completely different?
Additional stuff:
I want this to be functional without javascript/jQuery, but this
would be a nice addition in future so I don't want to rule it out if
possible.
The selection process is dependent on what was selected in the
previous step, so I can't just render the whole form in step one, and
some kind of refresh will be required.
First, i'd say you can't completely avoid javascript your selection process, if only for triggering change event on your selectors. Having user to manually trigger page refresh through some button doesn't seem like a good idea.
But if you're so inclined, you need to create a form controller with form builder, there just check a request and render a form accordingly.
For example, if no request is supplied it renders a starting form contains only one select and a submit button, and its action is simple submit to the same page. Main page controller includes a form controller, so form controller gets a request and renders second part and so on...
Context: When a visitor submits the comment form in Wordpress, I want to validate the data in preprocess_comment. If certain parameters are not met, I want to three things to happen:
The comment is not saved
The visitor returns to the page containing the form, its fields are prepopulated with the submitted values
The comment form is altered and an extra form element with a CAPTCHA is added.
I've tried to do something like this:
function myplugin_validate($comment) {
add_action('comment_form_logged_in_after', 'comment_form_captcha_field');
return $comment;
}
add_action('preprocess_comment', 'myplugin_validate');
function comment_form_captcha_field() {
echo "....";
}
This approach won't work though:
There is no way to stop the flow in preprocess_comment
Since comment_form_captcha_field() is never called, you won't return to a prepopulated comment form with the user submitted values.
There are of course "dirty" alternatives like storing the submitted values in a session, redirecting the user from preprocess_comment (wp_redirect) and catching the values from the session after reloading the page. Or I could intercept the submit handler through JS and go from there.
I wonder if there is a way to hook onto the comment system in Wordpress and do this without resorting to javascript, sessions and the likes.