14

We're using JSF 2.0 on WebSphere v8.5 with several component libraries PrimeFaces 4.0, Tomahawk 2.0, RichFaces, etc.

I am looking for generic mechanism to avoid form re-submission when the page is refreshed, or when the submit button is clicked once again. I have many applications with different scenarios.

For now I have considered disabling the button with a piece of JavaScript in onclick attribute, but this is not satisfying. I'm looking for a pure Java implementation for this purpose, something like the Struts2 <s:token>.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Sarz
  • 1,970
  • 4
  • 23
  • 43
  • Does Ajax over come the form re-submission issue? as only part of page is rendered, not whole page or redirection – Sarz May 07 '14 at 07:44
  • Disabling the onClick event will probably not be sufissiant a delay timer is required to do the trick – Nassim MOUALEK May 07 '14 at 10:38
  • Yes @NassimMOUALEK i achieve disabling of button until ajax complete its rendering – Sarz May 07 '14 at 11:52
  • its not exactly the problem that i was thinking about, when the user click multiple times, and very fast on the button, a delay before submit is required to decide if you should submit or not – Nassim MOUALEK May 07 '14 at 12:12
  • Right but i believe web page JS is much more faster than human (clicking again and again). first action performed onclick is disabling the button than ajax will enable this button when it complete its cycle. So by this no overlapping event will occur – Sarz May 07 '14 at 13:23
  • We have problem with BNP client, they use only IE browser, and beleave in IE user could click twice at the same time (what ever the page is), we handle the problem at Hibernate Transaction Level, but it could be fixed with the delay as i montion – Nassim MOUALEK May 07 '14 at 13:27

3 Answers3

18

I am looking for generic mechanism to avoid form re-submission when the page is refreshed

For that there are at least 2 solutions which can not be combined:

  1. Perform a redirect after synchronous post. This way the refresh would only re-execute the redirected GET request instead of the initial request. Disadvantage: you can't make use of the request scope anymore to provide any feedback to the enduser. JSF 2.0 has solved this by offering the new flash scope. See also How to show faces message in the redirected page.

  2. Perform the POST asynchronously in the background (using ajax). This way the refresh would only re-execute the initial GET request which opened the form. You only need to make sure that those forms are initially opened by a GET request only, i.e. you should never perform page-to-page navigation by POST (which is at its own already a bad design anyway). See also When should I use h:outputLink instead of h:commandLink?


or when the submit button is clicked once again

For that there are basically also at least 2 solutions, which could if necessary be combined:

  1. Just block the enduser from being able to press the submit button during the submit and/or after successful submit. There are various ways for this, all depending on the concrete functional and design requirements. You can use JavaScript to disable the button during submit. You can use JSF's disabled or rendered attributes to disable or hide the button after submit. See also How to do double-click prevention in JSF 2. You can also use an overlay window during processing ajax requests to block any enduser interaction. PrimeFaces has <p:blockUI> for the purpose.

  2. Validate uniqueness of the newly added entity in the server side. This is way much more robust if you absolutely want to avoid duplication for technical reasons rather than for functional reasons. It's fairly simple: put a UNIQUE constraint on the DB column in question. If this constraint is violated, then the DB (and DB interaction framework like JPA) will throw a constraint violation exception. This is best to be done in combination with a custom JSF validator which validates the input beforehand by performing a SELECT on exactly that column and checking if no record is returned. A JSF validator allows you to display the problem in flavor of a friendly faces message. See also among others Validate email format and uniqueness against DB.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • i am using `` in all forms of my applications, this `FlashScope` thing says to `redirect/reload` page. How can i tackle this? – Sarz May 20 '14 at 13:18
  • There's an example in "See also" link. – BalusC May 21 '14 at 06:34
  • Validating uniqueness in the server side might get complex. For example, I am sending a sms to my friend. In this case, there is no logic or constraint to check the uniqueness. Maybe, caching and matching the request would give you a hint, but even if we ignore the matching cost, there could be business situations where requests with same values is part of the norm. – Mashrur Jul 07 '15 at 01:46
3

Instead of creating a token manually, you can use BalusC' solution. He proposed a Post-Redirect-GET pattern in his blog

Alternative solutions can be found in these answers:

Manuel
  • 3,828
  • 6
  • 33
  • 48
  • when i put in h:commandButton now it is not re-submission the form. Does it full fill the requirement? – Sarz May 07 '14 at 10:37
  • The problem is we need double-submission enable and disable according to our scenario. – Sarz May 07 '14 at 11:53
0

<!--Tag to show message given by bean class -->
<p:growl id="messages" />

<h:form>
  <h:inputText a:placeholder="Enter Parent Organization Id" id="parent_org_id" value="#{orgMaster.parentOrganization}" requiredMessage="Parent org-id is required" />


  <h:commandButton style="margin-bottom:8px;margin-top:5px;" class="btn btn-success btn-block " value="Save" type="submit" action="#{orgMaster.save}" onclick="resetform()" />
</h:form>
    public String save() {
    FacesContext context = FacesContext.getCurrentInstance();
    context.getExternalContext().getFlash().setKeepMessages(true); //This keeps the message even on reloading of page

FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Your submission is successful.", " ")); // To show the message on clicking of submit button


return "organizationMaster?faces-redirect=true"; // to reload the page with resetting of all fields of the form.. here my page name is organizationMaster...you can write the name of form whose firlds you want to reset on submission

}
Vinod Chauhan
  • 888
  • 7
  • 8