Child pages
  • Multiple Submit Buttons
Skip to end of metadata
Go to start of metadata

You can be also interested in checking the page HTML form buttons HOWTO

Original solution

Introduction

Often, we have multiple submit buttons within a single form. The below is just a simple way of identifying which button was clicked, and which actions to take.

There are, of course, many ways of doing this, including the use of JavaScript to identify the actions, etc... You're welcome to pick and choose whichever method you find most useful. Struts 2 is flexible enough.

Form

<button type="submit" value="Submit" name="submit">
<button type="submit" value="Clear" name="clear">

Action with boolean properties

class MyAction extends ActionSupport {
   private boolean submit;
   private boolean clear;
   public void setSubmit(boolean submit) {
      this.submit = submit;
   }
   public void setClear(boolean clear) {
      this.clear = clear;
   }
   public String execute() {
      if (submit) {
         doSubmit();
         return "submitResult";
      }
      if (clear) {
         doClear();
         return "clearResult";
      }
      return super.execute();
   }
}

Explanation

The boolean properties 'submit' and 'clear' will be set to 'true' or 'false' according weather the submit or clear form element is present in the submitted form.

In this case, the properties are boolean, therefore the values set would be boolean.

There is another method, using String properties, described below...

Form

<button type="submit" value="Submit" name="buttonName">
<button type="submit" value="Clear" name="buttonName">

Action with String properties

class MyAction extends ActionSupport {
   private String buttonName;
   public void setButtonName(String buttonName) {
      this.buttonName = buttonName;
   }
   public String execute() {
      if ("Submit".equals(buttonName)) {
         doSubmit();
         return "submitResult";
      }
      if ("Clear".equals(buttonName)) {
         doClear();
         return "clearResult";
      }
      return super.execute();
   }
}

Explanation

In this case, the properties are String, therefore the values set are also String in nature.

I don't really like this method, as it ties in the Action to the Form. (What happens if you want different text to show up on the button ? You would have to change both the form as well as the corresponding action.)

Conclusion

There are other ways to achieve the same functionality. There are pros and cons to each methods. Feedback welcome.

Nyong Nyong's solution

This was originally taken from comment posted by Nyong Nyong to this page - you can see it here

The more elegant solution is probably by using multiple mappings for same Action. This way you don't need to set "struts.enable.DynamicMethodInvocation" to "true".

In JSP

<s:form method="post" action="mySubmitAction">
    <s:submit value="Submit"/>
    <s:submit value="Clear" action="myClearAction"/>
</form>

In struts.xml

<action name="mySubmitAction" class="MyAction" method="submit">
       <result>submit.jsp</result>
</action>
<action name="myClearAction" class="MyAction" method="clear">
       <result>submit.jsp</result>
</action>

Then in MyAction class

public String submit() throws Exception {
    // submit button logic here
    return SUCCESS;
}

public String clear() throws Exception {
    // clear button logic here
    return SUCCESS;
}


For best practice, if you have common data loaded / managed by your actions (submit & clear), then for example, you can define a MyBaseAction class, extended by MySubmitAction and MyClearAction class. Then this is how they looks like:

In struts.xml

<action name="mySubmitAction" class="MySubmitAction">
       <result>submit.jsp</result>
</action>
<action name="myClearAction" class="MyClearAction">
       <result>submit.jsp</result>
</action>

You don't need to specify a method name anymore, that means we will use the default execute() method.

Then in the MyAction, MySubmitAction and MyClearAction class

MyAction.java
public class MyAction extends ActionSupport {
    // common data or logic here
}
MySubmitAction.java
public class MySubmitAction extends MyAction {

    public String execute() throws Exception {
        // submit button logic here
        return SUCCESS;
    }
}
MyClearAction.java
public class MyClearAction extends MyAction {

    public String execute() throws Exception {
        // clear button logic here
        return SUCCESS;
    }
}

Credit: Andrea Ligios

  • No labels

13 Comments

  1. Unknown User (lfsoft)

    This doesn't work for all cases. If there are validation errors (e. g. a field is missing) the execute() method never will be executed.
    So you can't use this technique for a "cancel" button in a form with validation "errors".

  2. Unknown User (lucastex)

    This example isn't working...

    When we submit this form, the param interceptor try to set the "submit" or "clear" boolean to the text in 'value' field.

    To get this working, we have to build the buttons this way:

    <button type="submit" value="true" name="variable_A_Name">Button_A_Label</button>
    <button type="submit" value="true" name="variable_B_Name">Button_B_Label</button>

    Cya!

    1. Thanks, it works, although it doesn't work with <s:submit> tag.

  3. I tried to update the page but, unfortunately I don't have permission. A more elegant solution than setting booleans and using in if/else ladder in your action is to use the new features incorporated into Struts 2, the method attribute of the submit tag:

    //In the struts.xml
     <action name="Person!*" class="myorg.myproject.struts.PersonAction" method="{1}">
        <result name="PERSON_FORM">/pages/person_form.jsp</result>
        <result name="SUCCESS">/pages/success.jsp</result>
     </action>

    //in the JSP
    //this will call the save() method of your PersonAction
     <s:form action="Person">
     <s:textfield name="person.FirstName"/>
     <s:submit method="save" value="Save Person"/>

     //in the action
     private Person person;
     private PersonService service;
     public Person getPerson()
     {
        return person;
     }
     public void setPerson(Person person)
     {
        this.person = person;
     }
     public String save() throws Exception
     {
        service.save(person);
        return SUCCESS;
     }

    1. Thanks, it works but I had to set "struts.enable.DynamicMethodInvocation" to "true" first

  4. A solution which has been posted on the struts-user mailinglist:

    Ian Roughley wrote:
    >
    > you can always use <s:submit name="method:delete" value="Delete" /> and
    > <s:submit value="Execute" /> - then you don't need the logic to
    > determine which button was clicked in the execute() method, and you can
    > use the validation config below.

    This is an elegant solution.
    The Java Action would look contain the methods execute(), which is triggered by the second example tag and delete(), triggered by the first submit button.

    1. Same as previous, it works but you need to set "struts.enable.DynamicMethodInvocation" to "true" first.

      Also, it can be made a bit more elegant:

      <s:submit value="Delete" method="delete"/>

  5. The boolean properties solution doesn't work because the string Value can't be converted to boolean. You can use lucastex solution (see previous comments) or use this trick to make it work:

    private boolean submit = false;
    private boolean clear = false;
    
    public void setSubmit(boolean submit) {
      this.submit = true;
    }
    
    public void setClear(boolean clear) {
      this.clear = true;
    }
    

    The advantage of this solution is that it can be applied to <s:submit> tag.

    Reference: http://serpensalbus.com/blog/tricking-struts2-multiple-submit-buttons/

  6. But the more elegant solution is probably by using multiple mappings for same Action. This way you don't need to set "struts.enable.DynamicMethodInvocation" to "true".

    In JSP

    <s:form method="post" action="mySubmitAction">
        <s:submit value="Submit"/>
        <s:submit value="Clear" action="myClearAction"/>
    </form>
    

    In struts.xml

    <action name="mySubmitAction" class="MyAction" method="submit">
           <result>submit.jsp</result>
    </action>
    <action name="myClearAction" class="MyAction" method="clear">
           <result>submit.jsp</result>
    </action>
    

    Then in MyAction class

    public String submit() throws Exception {
        // submit button logic here
        return SUCCESS;
    }
    
    public String clear() throws Exception {
        // clear button logic here
        return SUCCESS;
    }
    


    For best practice, if you have common data loaded / managed by your actions (submit & clear), then for example, you can define a MyBaseAction class, extended by MySubmitAction and MyClearAction class. Then this is how they looks like:

    In struts.xml

    <action name="mySubmitAction" class="MySubmitAction">
           <result>submit.jsp</result>
    </action>
    <action name="myClearAction" class="MyClearAction">
           <result>submit.jsp</result>
    </action>
    

    You don't need to specify a method name anymore, that means we will use the default execute() method.

    Then in the MyAction, MySubmitAction and MyClearAction class

    MyAction.java
    public class MyAction extends ActionSupport {
        // common data or logic here
    }
    
    MySubmitAction.java
    public class MySubmitAction extends MyAction {
    
        public String execute() throws Exception {
            // submit button logic here
            return SUCCESS;
        }
    }
    
    MyClearAction.java
    public class MyClearAction extends MyAction {
    
        public String execute() throws Exception {
            // clear button logic here
            return SUCCESS;
        }
    }
    

    Credit: Andrea Ligios

    1. Can I add your comment as an additional solution ? Comments aren't exported with the docs :\