Friday, January 11, 2008

Struts Tip #1 - Use an ImageButtonBean to represent an image button.

An endless source of aggravation is the HTML input image element. The specification says that browsers should treat this control like an image map. Unlike other buttons, it does not submit a string representing the button's label, it submits the X and Y coordinates. If you look at the HTTP post for an image button, you'll see it looks something like this
myImageButton.x=200
myImageButton.y=300
For most other controls, a Struts developer can create a simple String property to represent the element. This clearly won't work with an image button, because it submits two "dotted" properties instead of a simple "name=value" entry like other elements.
Happily, Struts allows an ActionForm to contain, or nest, other JavaBeans, and will automatically populate the beans using the same syntax as the image element. (What a co-inky-dink!)
To represent an image input element in your ActionForm, say what you mean, and use an ImageButtonBean to capture the X and Y parameters.
public final class ImageButtonBean extends Object {
private String x = null;
private String y = null;
public String getX() {
return (this.x);
}
public void setX(String x) {
this.x = x;
}
public String getY() {
return (this.y);
}
public void setY(String y) {
this.y = y;
}
public boolean isSelected() {
return ((x!=null) (y!=null));
}
} // End ImageButtonBean
Note that we've included a helper method on this bean, isSelected(). This just returns true if either the x or y property is not null. If both are still null, then isSelected() returns false.
Here's how you could declare two ImageButtonBeans on an ActionForm.
// ..
private ImageButtonBean logonButton = new ImageButtonBean();
public void setLogonButton(ImageButtonBean button) {
this.logonButton = button;
}
public ImageButtonBean getLogonButton() {
return this.logonButton;
}
private ImageButtonBean cancelButton = new ImageButtonBean();
public void setCancelButton(ImageButtonBean button) {
this.cancelButton = button;
}
public ImageButtonBean getCancelButton() {
return this.cancelButton;
}
// ...
The next question will be "OK, which button did they push?", so let's define another helper method on the ActionForm to tell us.
public String getSelected() {
if (getLogonButton().isSelected()) {
return Constants.LOGON;
}
if (getCancelButton().isSelected()) {
return Constants.CANCEL;
}
return null; // nobody home
}
In an Action, determining which button is pressed is then a simple matter of asking the form what was selected.
String selected = ((myForm) form).getSelected();
if (Constants.CANCEL.equals(selected)) ...
Of course selected doesn't need to be a String; it could be an int, a custom type to represent your API functions, or even the name of another method for use with a DispatchAction.
Using "API helper methods" on ActionForms, as we did with getSelected(), is a very useful technique. We'll use it again in Tip #2, when we discuss the standard Dispatch Actions.

No comments: