Jump to content
choppingblock

Prevent form resubmission

Recommended Posts

Hey all,

I have just created a contact form with the PW api (nice and easy as expected, though I found it has some limitations concerning fieldsets and multi-row layout... I know this is a tricky subject, so no offense meant).

I'm wondering what would be the best way to prevent the (accidental) resubmission of a form. I usually do this with a redirect after submit and a flash error/success message... is there any PW-ish way to achieve this (e.g., does PW support flash messages, or is this procedure even already implemented in the api somewhere)?

Share this post


Link to post
Share on other sites

Hi choppingblock,

Do you mean preventing the user from clicking submit multiple times?

If so, I usually just handle that with JS.

$("form").submit(function() {
    $(this).submit(function() {
        return false;
    });
}); 
  • Like 2

Share this post


Link to post
Share on other sites

Sometimes I also add a loader icon next to the submit button.

  • Like 1

Share this post


Link to post
Share on other sites
Do you mean preventing the user from clicking submit multiple times?

I am more concerned about people reloading the page (like, pressing F5) after the form has been submitted.

So I'd like to redirect them to the same page, but without any POST data. And sending a flash message with the redirect (message that is only stored in the session until the next page is displayed).

...and there it is, thanks a lot.

Share this post


Link to post
Share on other sites

I implement the PW CSRF token in my forms so a resubmit will result in a error message.

  • Like 3

Share this post


Link to post
Share on other sites

ah,

gotcha now. Yep, you are on the right track.

I do exactly that.

:)

Share this post


Link to post
Share on other sites

I implement the PW CSRF token in my forms so a resubmit will result in a error message.

this seemed not to work with my form, although it generates the token (i guess i have to check for it somehow after submit)... can you give an example of how you do this?

Share this post


Link to post
Share on other sites

If you use PW form API, it will get validated if you call processInput()

$form->processInput($input->post);

I think the CSRF doesn't get reset if the CSRF was valid, but you can do it manually with

$session->CSRF->resetToken();

after validating the form.

Or if you do manual form and not use InputfieldForm you can generate and validate the token

$session->CSRF->validate(); // will throw exeption if invalid

And get the token name and value with it respective methods

$session->CSRF->getTokenName(); // name for input hidden
$session->CSRF->getTokenValue(); // token value

Also the trick renobird mentioned is also very good to prevent double click submission errors.

Of course you can still use redirect method and as you may found the $notices errors and messages are transported through redirects.

  • Like 5

Share this post


Link to post
Share on other sites
$session->CSRF->resetToken();

this is what i was missing... thanks!

Edit:

Got it working with CSRF token, but I think the redirect approach fits better here. Easy to achieve with the flashdata function of PW (this should be added to the cheat sheet, I could imagine many users of PW would use this if they knew about it).

  • Like 1

Share this post


Link to post
Share on other sites

this is what i was missing... thanks!

Edit:

Got it working with CSRF token, but I think the redirect approach fits better here. Easy to achieve with the flashdata function of PW (this should be added to the cheat sheet, I could imagine many users of PW would use this if they knew about it).

You made my day! Missed the CSRF reset as well^^

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Peter Knight
      I have a few web forms which require testing on a weekly basis and I don't want the recipients (administrators) to receive these test emails.
      What would be a good way to test approx 15 forms from the front end and have the test delivered a list of secondary administrator recipients?
      I'm thinking that I could have some kind of config file which watches for a trigger word or email and then understands that it's a test and to bypass the normal admins?
      All of the forms ask for an email address so I could setup an email such as 'testform@email.not' etc which my config file (hook?) would watch for.
      Or is there a better way to do this?
      Additionally, I have a few extra requirements...
      Forms should goto an alternative success page. This is because I don't want my test to skew my Google Analytics conversion tracking Forms would need to be tested from the front-end and not the PW admin area Any advice appreciated.
      BTW I realise this should be posted in the proper FormBuilder support forum. I am in the process of renewing my license for access to that support forum.
       
    • By J_Szwarga
      What is the best practice for having a form (only accessible to a logged in user) save the user's progress between sections of the form? Fieldsets? Multiple forms?
      Use case: I have a very long application form that would take 30 minutes for the applicant to fill out and I would hate for all progress to be lost due to user error. The progress needs to be logged into the user's page.
      Thanks!
    • By Guy Incognito
      I'm trying to implement a front-end image upload form for user profile pictures, to a field called 'profile_picture'. The code is based on the various examples found around these forums but isn't yet 100% right.
      The form successfully submits the image to the server and updates the field in the dashboard. When you submit the firm, the page reloads and uploads the image but the template still loads the old image path (now broken path as the old image has been removed).
      I can only get the new image to show if I hit enter in the address bar forcing the page to reload.
      Any ideas? Is it a caching issue, or something to do with the order of the script? It makes no difference if I call the image after the upload form.
      <?php //Display current user image $userImg = $user->profile_picture->first(); echo '<img src="'.$userImg->url.'">'; $upload_path = $config->paths->assets . "files/avatar_uploads/"; $f = new WireUpload('userimage'); $f->setMaxFiles(1); $f->setMaxFileSize(1*1024*1024); $f->setOverwrite(true); $f->setDestinationPath($upload_path); $f->setValidExtensions(array('jpg', 'jpeg', 'png', 'gif')); if($input->post->form_submit) { if(!is_dir($upload_path)) { if(!wireMkdir($upload_path)) throw new WireException("No upload path!"); } $files = $f->execute(); if ($f->getErrors()) { foreach($files as $filename) @unlink($upload_path . $filename); foreach($f->getErrors() as $e) echo $e; } else { $user->of(false); $user->profile_picture->removeAll(); // wirearray (line added by @horst: explanation is three posts beneath) $user->profile_picture = $upload_path . $files[0]; $user->save(); $user->of(true); @unlink($upload_path . $files[0]); } } ?> <form class="forum-form" accept-charset="utf-8" action="./" method="post" enctype="multipart/form-data" > <input type="file" id="attach" name="userimage" accept="image/jpg,image/jpeg,image/gif,image/png" /> <input type="submit" name="form_submit" value="Submit"/> </form>
       
    • By Kiwi Chris
      Forms are an essential part of most websites, and it's no surprise that there's an excellent premium module Form Builder but what if you're on a zero budget for whatever reason?
      It is possible to build forms quickly and easily by making use of a couple of free modules and the admin UI to give you a great deal of flexibility and speed of development, particularly if you need multiple forms on a website with different fields.
      1. First you're going to need to install a couple of modules:
      Form Template Processor
      Fieldtype Select External Option
      2. For each form that you want to display, create a template without a template file and add fields to it as you normally would. (eg I have formContact, formRegister etc)
      Tip: under the Advanced tab in the setup for each template, I add a tag Forms so that all my forms templates are nicely grouped together in admin.
      3. Create a new field of type Select External Option and call it formTemplate
      In the section Create options from any database table select
      templates as the source table id as the Option Value name as the Option Label 4. Create a new template file and call it renderForm.php (or whatever else you like)
      Add an email field to this form - This will be the email address that forms get submitted to. Add the formTemplate field you previously created to this form. This will allow you to select which of the templates you previously created such as formContact, formRegister etc you want to render. Add any other fields as usual that you want to render on the page. Add the following PHP code to the template file. $recipient = $page->email; $form = $modules->get('FormTemplateProcessor'); $form->template = $templates->get($page->formTemplate->label); // required $form->requiredFields = array('contactName', 'contactEmail', 'contactMesssage'); //Optional: This can be improved by having a field in the page template with a CSV list of required fields eg $form->requiredFields = explode(',', $page->requiredFields) $form->email = $recipient; // optional, sends form as email. FormTemplateProcessor can also save forms to the database. $content .= $form->render(); //generate the form to display. Note: this doesn't actually render the form at this point, but you have it in the $content variable ready to output wherever you want in your template.
      Add any template HTML or other PHP code and echo $content; wherever you want to render the form.
      5. Create a page using the renderForm template, and provide an email address, and select a form that you want to display.
      6. Use CSS to style the form as required.
      7. View your new page, and check that the form renders correctly.
      8. You can modify the templates you created at step 2 or create new ones as required if your requirements for what fields forms display changes.
      Note: The Form Template Processor module can also save form input as pages, and the FieldType Select External Option can be set up with filtering, so this solution can probably be refined further.
    • By cleanboy
      Hey all,
      Mods; please feel free to move this if it is in the incorrect place although I thought this was the best place for it.
      Kinda new to processwire but getting the hang of it....I am trying to build a payment form with the Stripe platform but failing miserably....I really hope someone can help!
      So I am building my form with the PW API and also following through this documentation here: https://stripe.com/docs/elements and here: https://stripe.com/docs/charges
      My form is pretty basic just for testing purposes right now:
      <form id="payment-form" class="pusher" name="payment-form" method="post" action="./#booking-form"> <?php $tokenName = $this->session->CSRF->getTokenName(); $tokenValue = $this->session->CSRF->getTokenValue(); echo '<input type="hidden" id="_post_token" name="' . $tokenName . '" value="' . $tokenValue . '"/>'; $out = ""; $out .= '<div id="card-number"></div> <div id="card-errors"></div>'; // create a new form field (also field wrapper) $form = $modules->get("InputfieldForm"); $form->action = "./"; $form->method = "post"; $form->attr("id+name",'payment-form'); // First Name $field = $modules->get("InputfieldText"); $field->skipLabel = true; $field->attr('id+name','name'); $field->attr('placeholder','Full Name'); $field->required = 1; $form->append($field); // append the field to the form // create email field $field = $modules->get("InputfieldEmail"); $field->attr('id+name','email'); $field->attr('placeholder','Email'); $field->required = 1; $form->append($field); // append the field // oh a submit button! $submit = $modules->get("InputfieldSubmit"); $submit->attr("value","SUBMIT"); $submit->attr("id+name","submit"); $submit->attr("class","cta white"); $form->append($submit); if($input->post->submit) { // user submitted the form, process it and check for errors $form->processInput($input->post); if($form->getErrors()) { // the form is processed and populated // but contains errors $out .= $form->render(); } else { foreach($input->post as $key => $value) echo htmlentities("$key = $value") . "<br />"; } } else { foreach($form->children as $input){ $out .= "<div class='col-sm-6'>{$input->render()}</div>"; } } echo $out; ?> </form> That alone works fine and returns all of the fields values after I click submit which is great...now we add the javascript:
      //Stripe var stripe = Stripe('pk_test_*****************'); var elements = stripe.elements(); // Custom styling can be passed to options when creating an Element. var style = { base: { // Add your base input styles here. For example: fontSize: '16px', lineHeight: '24px' } }; // Create an instance of the card Element var card = elements.create('card', {style: style}); // Add an instance of the card Element into the `card-element` <div> card.mount('#card-number'); card.addEventListener('change', function(event) { var displayError = document.getElementById('card-errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } }); // Create a token or display an error when the form is submitted. var form = document.getElementById('payment-form'); form.addEventListener('submit', function(event) { event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // Inform the user if there was an error var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // Send the token to your server stripeTokenHandler(result.token); } }); }); function stripeTokenHandler(token) { // Insert the token ID into the form so it gets submitted to the server var form = document.getElementById('payment-form'); var hiddenInput = document.createElement('input'); hiddenInput.setAttribute('type', 'hidden'); hiddenInput.setAttribute('name', 'stripeToken'); hiddenInput.setAttribute('value', token.id); form.appendChild(hiddenInput); // Submit the form form.submit(); } This gives an error in the console: Uncaught (in promise) TypeError: form.submit is not a function. 
      This is because our submit input has the name "submit". Ok thats cool...I can change that but once I do the page essentially refreshes and the form just shows again and it doesnt give me the values it did before....I guess it isnt posting? either way after I submit the form after changing the name of the submit button the form just loads again and anything inside: if($input->post->submit) doesnt seem to execute...so what gives?
      If anybody here has done this before with PW 3+ I would really love an example of how to use this to the point of sending information to Stripe.
      I have installed Stripe with composer and it would appear that I can refer to it in Processwire just fine...my problem is just getting to the point where I need to refer to it which is after the submit.
      I have seen the PaymentStripe module but tbh the documentation on that is somewhat lacking and im not even sure it works with the latest version of stripe? Im also not sure how to integrate that into a form either unless you use something along the lines of the example code provided after the form has been submitted but I cant even seem to submit the form to even try that and im not really sure why.
      Here is the PaymentStripe module page for those wondering: https://modules.processwire.com/modules/payment-stripe/
      Any help would be greatly appreciated!
      Cleanboy
×
×
  • Create New...