Struts ActionForm validate() question

I’m trying to setup a simple contact us form that gathers information from a user, checks that the information is valid and then emails the information off to a third party using Struts v1.1, specifically an ActionForm and an Action. In my struts-config.xml, under <action-mappings>, I have this:

<action
  path="/contact/requestinfo"
  type="com.mycompany.actions.RequestInfoAction"
  name="requestInfoForm"
  scope="request"
  validate="true"
  input="/views/requestinfo.jsp">
  <forward name="success" path="/views/requestinfo_confirm.jsp"/>
</action>
    

and then obviously a <form-bean> definition above that. What I expected to happen was that the initial request would be forwared to the page specified by the input attribute, the user would then submit the form, the validate() method would be called on the ActionForm instance, and then if the validate() method return no ActionErrors, the form would be passed on to the Action. What happens instead is that the validate() method is called on the ActionForm before the user even submits the form, which causes the error messages (“First name is a required field.”) to be displayed before they have even submitted the form.

In the short-term, the workaround is to define an action mapping that simply forwards the user to the input page and then a second mapping that has the validate=true attribute set, so the page flow looks like this:

/contact/requestinfo –> display form –> submit form –> /contact/requestinfoform –> validate() –> if no errors, then servlet forwards to the Action

Is there a way to have to validate() method not called on the intial load of the page? Any thoughts?

12 thoughts on “Struts ActionForm validate() question”

  1. Override the validate() method in your form and then check request parameters or attributes to determine if you should call super.validate(). If not, then simply return null.

  2. Thanks Matt. I already had overridden the validate() method. That doesn’t seem to help… and calling super.validate(mapping,request) does nothing since the validate() method of the ActionForm class does nothing but return null every time.

    I guess I was thinking that the framework would recognize that no form had yet been submitted and thus wouldn’t call the validate() method, BUT wouldn’t allow the execute() method to be called on the Action either… almost like it would just forward to the input form without calling either validate() in the ActionForm or execute() in the Action.

    I modified the Action subclass so that now I check for an HTTP POST, if the post exists, then I manually call the validate() method of the form, check for errors, and then either call mapping.findForward(“success”) (to forward to the confirmation page) or mapping.getInputForward() (to forward the user back to the input screen)

  3. There really is no better way (that I know of). I make two action mappings – one to go to the form without validation (I call this the setup action) and then one that is the submit action.

    One piece of Struts wisdom I do have regarding validation though – use the Validator framework and do validation declaratively in validation.xml. Even slicker, use XDoclet to generate validation.xml using the strustvalidationxml subtask of webdoclet.

  4. maybe I am missing something but I was wondering, why doesn’t your form bean extend org.apache.struts.validator.ValidatorForm ?

    you don’t need to override the validate() method in that case

    works for me

  5. Struts instantiates the form (only if no existing instance is already in scope) you define in the actionMapping when the page is loaded and then use it for all actionMappings that share the form. Normally you would have one form per page, but you may have one form for all pages. If you are sharing the form this way, validation will apply to all fields when yu are trying to get out of the previous page. Perhaps a field with the same name is declared in the pevious page?.

  6. If the validate method of a ActionForm returns some error the request is forwarded to the same JSp from where the data was submitted and the errors are displayed on that JSP
    Is there any way i can forward the validation errors to a different JSP

  7. Hi,

    I’m currently developing an action form which contains customer details. Within this form you have the normal details and an address object. Is it possible to access such a structure using normal JSP tags or do I have to flatten the address down into another action form?

    Thanks

    Simon

  8. hi Simon,

    You can usually access the structure of an object stored in a form
    using this syntax like this (where customer is your form bean, address
    is the object you’ve stored in your form bean and city is a property
    of the address object)

    ${customer.address.city}

    See if that works…

    AJ

  9. I’ve come up with what I think is a fairly simple and elegant solution to this problem:

    1) Add the following code to your ActionForm:

    private boolean formIsLoaded = false;

    public boolean getFormIsLoaded() {
    return formIsLoaded;
    }

    public void setFormIsLoaded(boolean formIsLoaded) {
    this.formIsLoaded = true; // should only EVER be called to set this to true
    }

    2) Add the following to your JSP page within the tags:

    #html:hidden property=”formIsLoaded” value=”true”/ #

    NOTE: in order to get this to post correctly I needed to change the “>” and “<” signs to #. You will need to change them back .

    3) Modify the validate method of your ActionForm to be:

    if (formIsLoaded) {
    // do all your validation here
    }

  10. I AM UING VALIDATION FRAM WORK
    before the user even submits the form, which causes the error messages (”First name is a required field.”) to be displayed before they have even submitted the form

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>