-
Notifications
You must be signed in to change notification settings - Fork 17
WButton
WButton is a component for making buttons. Buttons are useful but must be accessible.
The helper classes WCancelButton and WConfirmationButton exist as backwards-compatibility to very old versions of WComponents.
- Why use WButton
- Accessibility
- WButton interactions
- Creating a WButton
- Adding a button action
- Rendering modes
- Confirmation of actions
- Images in buttons
- HTML output
- Disabling
- Hiding
- Testing
- Styling
- Related components
- Further information
WButton is used to invoke Actions. Commonly these are Actions defined in the Java application and a WButton is used to trigger a http POST or Ajax request which willersult in the action being undertaken. A subset of this is the actions associated with a WTable, which can only be invoked by a WButton. WButton may also be used to invoke JavaScript actions.
Most of the common use-cases for WButton may be equally undertaken using WMenuItem. If a number of different actions are to be placed together in a UI then there is some advantage in using a WMenu rather than a set od WButtons as WMenu has quicker kwyboard access.
WButton will be accessible if it is created with a reasonable labelling string - even if this string is not displayed on the final button because an image is displayed as the only content of the button.
WButton saveButton = new WButton("Save");
At a bare minimum a WButton must have at least one of:
- a displayed text label (preferred);
- a toolTip which adequately describes the purpose of the button; or
- setting the accessibleText property to a value which adequately describes the purpose of the button.
For detailed information and methods to ensure your WButtons are always accessible see WButton accessibility.
A WButton may be given an access key to provide rapid keyboard access.
A button which has visible text or an image should almost never have a toolTip set. When it is set it must not simply repeat the visible (or image alternate) text. A tooltip may be appropriate when the button needs further clarification or if it contains only an icon. See toolTip.
// with WButton `button`
button.setToolTip("Further context for this button");
// if a button contains only an icon, set a toolTip
WButton helpButton = new WButton();
helpButton.setHtmlClass(HtmlIconUtil.HELP_ICON);
helpButton.setToolTip("help");
// NEVER do this:
WButton saveButton = new WButton("Save");
saveButton.setToolTip("Save");
// even if an image is added
saveButton.setImage(SAVE_BUTTON_IMAGE);
If a WButton has an Action which results in a WPopup being added to the view then the button must be flagged as having a pop-up. This property is set using setPopupTrigger
. For details about the use of this property see WButton accessibility.
Note that this does not apply to WPrintButton which cannot invoke a WPopup.
Under normal (and therefore default) conditions a WButton is used to invoke a form submission which will cause a complete HTTPS post to the server application. The following settings will (in order) change this default interaction.
- If the WButton is a trigger for a WAjaxControl then the ajax request will be triggered and the button will not invoke a form submission.
- If the WButton is a WDialog trigger component it will launch the dialog but not POST the form.
- If the
clientCommandOnly
propertyis settrue
the WButton will never submit the form but may invoke an Ajax request if the WButton is a trigger for a WAjaxControl depending on how the client side command is written and all other interactions of the button are dependent on the commands supplied. - If the WButton has its cancel property set it will require confirmation before posting the form if either:
- the user has made changes; or
- there are unsaved changes on the server as flagged by the WApplication or WButton's unsavedChanges property.
- If the WButton has a
msg
property set it will require confirmation before submitting the form.
WButton has three constructors: use of the default constructor will require that the button's text content, toolTip or accessibleText must be set later.
// a default WButton
WButton button = new WButton();
// a WButton with a text label
WButton button = new WButton("Submit");
// a WButton with a text label and access key
WButton button = new WButton("Submit", 'S');
Unless the button has an Action set or is in one of the conditions outlined in WButton interactions a simple WButton will submit the current form view but do nothing.
Mostly we want our buttons to do something useful. This is usually done by setting the button Action. Under some circumstances, though, the button is used to undertake a custom JavaScript action in the client only. In this case the clientCommandOnly property is set true
and the button has no Action.
For most common use-cases the button Action will be performed after POSTing the view back to the application server. If the button remains in the view which is shown after the action takes place it will usually gain focus. This may be adjusted if the view shows WValidationErrors or if another component is set as the component to focus.
WButton button = new WButton("Submit");
button.setAction(new Action() {
@Override
public void execute(final ActionEvent event) {
// Do something useful
}
});
Note that this does not apply to WPrintButton which cannot invoke an Action.
The button action may be used to validate user input. In this case the Action applied is a ValidatingAction and the form segment to be validated is passed to the action.
// given WButton button, WMessages messages and form segment validationTarget
button.setAction(new ValidatingAction(messages.getValidationErrors(),
validationTarget) {
// If custom validation scenarios are required then
// override validate.
@Override
public void validate(final List<Diagnostic> diags) {
super.validate(diags);
// add custom validation scenarios
}
// The application usually wants to do something useful
// if the input is valid. This method MUST be overridden.
@Override
public void executeOnValid(final ActionEvent event) {
// things to do if valid
}
// The default action on invalid is to set up error messages.
// If the application has custom actions to undertake when invalid
// input is present it is done by overriding executeOnError.
@Override
executeOnError(final ActionEvent event, final List<Diagnostic> diags) {
super.executeOnError(event, diags);
// do custom error stuff.
}
});
Note that the only part of the view which is validated is that within the WComponent passed to the ValidatingAction. This may result in accessibility problems in some circumstances as partial screen validation conflicts with some interpretations of WCAG 2.0.
The form segment to validate is passed to the UI as the validates
property. This enables client side validation (if enabled) to do sub-form validation which is not available in native HTML 5 validation.
To reduce inconsistency and potential for error and to maximise accessibility one should always specify what part of a screen is subject to input validation. In many cases this will be the entire form.
A custom UI command may be attached to a WButton using custom JavaScript. Such a command would commonly be attached as a click event handler on the document body element with a test for a particular button description using a static id or custom HTML class attribute value(s).
Adding such a command to a UI will allow any button matching the selector for the event handler to invoke the command. WButton, under normal circumstances, will cause a submit action when it is invoked. There are two ways to prevent this:
- mark the button as invoking a client side command only by using the clientCommandOnly property; or
- ensure the invoked action prevents propagation or the default action of a button.
If the button is to run a client command and make an Ajax call then one should not prevent propagation in the JavaScript click handler as this will also prevent the Ajax call being made.
Note that this does not apply to WPrintButton which cannot invoke a UI command other than the browsers configured print
dialog.
A WButton can be set to invoke only a JavaScript action and not undertake a submission by setting the clientCommandOnly
property. This boolean property is used to tell the client code that the button should not fire a form submit action when it is invoked. It does not create a client command: that has to be attached to the UI as custom JavaScript.
WButton clientOnlyButton = new WButton(labelText);
clientOnlyButton.setClientCommandOnly(true);
// Some more work may be needed to ensure the command is fired only by
// this button. One way to do this is to set a static id on the button.
clientOnlyButton.setIdName("clientcommandbutton");
If this property is set true
then the WButton may still act as a trigger for a WAjaxControl but will not fire a server action. So doing something like the following is probably a waste of effort unless the button is also a trigger for a WAjaxControl.
WButton clientOnlyButton = new WButton(labelText);
clientOnlyButton.setClientCommandOnly(true);
clientOnlyButton.setAction(new Action() {
@Override
public void execute(final ActionEvent event) {
// This action will never be invoked.
}
});
Commands run in the client are written in JavaScript and may be attached in any one of several ways. The preferred method is to write a JavaScript file and attach it to the application using WApplication's addJsFile()
methods. For more information see Adding custom JavaScript.
If a command is only required for a specific view it can be attached along with the command button. One might, for example, attach a JavaScript file to the UI when first preparing to paint a button instance:
WButton clientOnlyButton = new WButton(labelText) {
@Override
protected void preparePaintComponent(final Request request) {
if (!isInitialised()) {
// add a JavaScript resource to the WApplication ancestor
WebUtilities.getAncestorOfClass(WApplication.class, this)
.addJsFile(SCRIPT_RESOURCE_PATH_AND_FILE);
setInitialised(true);
}
super.preparePaintComponent(request);
}
};
clientOnlyButton.setClientCommandOnly(true);
The script element could be added directly to the UI along with the button but this has a number of disadvantages so is not generally recommended.
One should note that whilst much of the discussion of client-only commands has assumed the button is clicked (or its equivalent to fire a click event) a command may be added to any event which is able to be fired on a button element so one could, for example, use a combination of touch, mouse and key events to provide rich, accessible interactions which are not built into a current WComponent. These actions may be attached to items which are not WButtons but only WButton requires the extra flag that it is not to submit the form when invoked.
WButton may render as a regular button, which is the default and recommended rendering, or with the appearance of a link. Note that having a button take on the appearance of a link may cause accessibility and usability problems so should be avoided where possible; this option is included to maintain compatibility with an obsolete design paradigm from a time when buttons were difficult to style and links were used to invoke commands.
These buttons are still buttons and you may create a usability issue by implementing this type. A typical button of this type may look like: .
To implement this appearance one would use the method setRenderAsLink(boolean)
:
WButton linkLikeButton = new WButton("Link");
linkLikeButton.setRenderAsLink(true);
// to remove the LINK appearance:
linkLikeButton.setRenderAsLink(false); // duh!
It is recommended that this option not be used except when the button is to display only an image and that image could reasonably be inferred to be a button by users.
- With default (button) rendering:
- With link-like rendering:
There are two mechanisms which will result in a user being asked to confirm a button click. If the WButton has its cancel
property set true
the user will be asked to confirm the cancel action if there are unsaved changes. If the button has its msg
property set to a non-empty String the user will always be asked to confirm the action (unless the cancel
property is also set in which case the action will only need to be confirmed if there are unsaved changes).
Note that this does not apply to WPrintButton which does not implement any form of user confirmation.
This is a Boolean property. If set true then the WButton will act as a cancel button and the user will receive an unsaved changes warning if:
- the user has made changes in the current screen; or
- the application has set an unsaved changes flag.
WButton cancelButton = new WButton("Cancel");
cancelButton.setCancel(true);
The default unsaved changes warning is set by Java property. Custom messages may be presented by using the msg
property.
WButton cancelButton = new WButton("Cancel");
cancelButton.setCancel(true);
cancelButton.setMessage("Are you sure you want to do that?");
The helper class WCancelButton sets this property by default. The default message may be overridden using setMessage(String)
as described below.
WCancelButton cancelButton = new WCancelButton("Cancel");
If the current page is part of a multi-page operation and the updates are not saved until the entire operation is complete an individual button with its cancel
property set true
may also be flagged to indicate there are unsaved changes in the process. If any cancel-button in a view has this flag then all cancel buttons will warn of unsaved changes and require confirmation even if the user has not made any changes in the current view.
//with WButton cancelButton
cancelButton.setUnsavedChanges(true);
In legacy systems which rely on full HTTP posts it may be easier or more appropriate to flag a WApplication as having unsaved changes but using this flag on a WButton allows it to be set when the process involves AJAX updates.
Note that a user will receive an unsaved changes warning if a cancel button is invoked if they have changed the state of data input controls in the current view even if the unsavedChanges
property is not set on any WButton or the WApplication; equally if any one WButton has this property set to true
then the unsaved changes warning will be given on invocation of any cancel button.
This property is set to create a custom confirmation message for the WButton. If set the user will have to confirm that they wish to undertake the action. If the cancel
property is set true then this message will only appear if there are unsaved changes.
WButton confirmDeleteButton = new WButton("Delete");
confirmDeleteButton.setMessage("Are you sure?");
The helper class WConfirmationButton sets this property to the default confirmation message. This may be changed using the setMessage(String)
method as per WButton.
WConfirmationButton confirmDeleteButton = new WConfirmationButton("Delete");
A button may contain an image and text or an image alone. The image is added as an ImageResource or WImage. If the image is to appear along with text then the imagePosition property must also be set.
Thie method setImage
is used to set an image as the content of the button. Any image may be used and it is output as a HTML image element. If this property is specified without an imagePosition property then the image will be the only content of the button. In this case the string value of the WButton is used as the 'alt' attribute of the image and must be specified. For details of how to create one of these see WButton accessibility.
WButton imgButton = new WButton("Save");
imgButton.setImage("/path/to/save_icon.png");
For most cases it is recommended that the inbuilt iconography (by default using Font Awesome) be used instead of static images. See HtmlClassProperties and HtmlIconUtil for more information.
To display the text label of a button along with an image the imagePosition property must be set. This property has four available values:
-
NORTH
- the image will appear centred above the button text; -
EAST
- the image will appear to the right of the button text; -
SOUTH
- the image will appear centred below the button text; and -
WEST
- the image will appear to the left of the button text.
WButton imgButton = new WButton("Save");
imgButton.setImage("/path/to/save_icon.png");
// put the image to the WEST of the text.
imgButton.setImagePosition(ImagePosition.WEST);
WButton will output a HTML button element of type submit
or (if the clientCommandOnly property is true
) of type button
.
A WButton may be disabled on page load. When disabled the WButton will not respond to user input or interaction.
This property may be used in conjunction with WSubordinateControl controls to enable or disable content without making another server call. In this case it is not necessary to explicitly set the disabled state as this will be managed by WSubordinateControl.
A WButton may be hidden on page load. When hidden the WButton is not available to any compliant user agent. It is present in the source and is not obscured in any way, nor is it disabled. This property is determined by a WSubordinateControl.
// button to open help window:
WButton button = new WButton("Pup me up a useless window");
button.setAction(new Action() {
@Override
public void execute(final ActionEvent event) {
// Do something which opens a WPopup...
}
});
button.setPopupTrigger(true);
WPopup is itself extremely controversial as it poses grave accessibility and usability problems and is under review.
WButton is a simple HTML button element so may be accessed in Selenium using any mechanism to acquire a WebElement.
// with WebDriver driver...
WebElement button = driver.findElement(By.cssSelector(".wc-button"));
A typical application may contain many WButtons however and iterating through a List<WebElement>
to get a specific one may be a bit irritating after the 400th time. In light of this the wcomponents-testlib module provides a WebElement
extension SeleniumWButtonWebElement
and SeleniumWComponentsWebDriver has methods to access WButton elements as SeleniumWButtonWebElement
.
-
SeleniumWButtonWebElement findWButtonByText(String)
will find the first WButton containing the given text as visible text or in the button element'stitle
andaria-label
attributes. -
SeleniumWButtonWebElement findWButtonByText(String, boolean)
will find the first WButton containing the given text with the option to also hunt in the button element'stitle
andaria-label
attributes for the text. -
SeleniumWButtonWebElement findWButtonByText(String, boolean, int)
will find thenth
WButton containing the given text with the option to also hunt in the button element'stitle
andaria-label
attributes for the text.
SeleniumWButtonWebElement
also provides a static method to access a CSS selector for WButtons, for use in By.cssSelector()
:
SeleniumWComponentsWebDriver driver = getDriver();
WebElement button = driver.findElement(By.cssSelector(
SeleniumWButtonWebElement.getCssSelector()));
The default appearance of WButton in WComponents allows buttons to inherit font styles. This will have a significant impact on browser default buttons which is most noticeable on iOS. A theme may change or override styles for all buttons in Sass or change or override just the styles for WButton. The following information, therefore, is applicable to the default theme but may vary from theme to theme.
WComponents provides some classes which may be applied to WButton to change the default appearance. The most common of these is to make the button appear similar to a link (a element). This style should be applied by using the renderAsLink property.
WButton may have one or more customised values added to its HTML class
attribute ising the htmlClass
property. This can be used for fine-grain styling of specific components but should be used with care. For more information see WComponents HTML class property.
WButton imgButton = new WButton("Help");
// to set class attribute values on the HTML output
cbSelect.setHtmlClass("wc-icon-after fa-question-circle");
There are a set of HTML class attribute values which may be applied to a WButton to change its style, but the actual styles not necessarily defined in the default theme. These classes are:
-
wc-nobutton
removes all common button artefact styling from the button and changes the font styles and metrics (if required) so that the text looks like normal text. This style should rarely or never be used by itself as it causes the infamous "mystery meat" anti-pattern. It may be useful in combination with other styles though or as a start point to re-style an instance of WButton based on a custom class value. It is used on many inbuilt controls such as the button which is created as a WMenuItem. -
wc-linkbutton
makes the button have the appearance of an unvisited link (a element) and is used, for example, when a WButton is used with link-like rendering. This class should not normally be used with WButton as the methodsetRenderAsLink(true)
should be used instead.
A theme may add other helper classes and expose them through convention to consuming applications. The following common classes may be applied to WButton:
-
wc-invite
adds hover/focus effects. If this class is set on a WButton then it is strongly recommended that a style be set on the button which at a minimum sets a border. This is because changing the background of a button will affect the border on many platforms causing a significant change in the appearance and size of a button. -
wc-icon
,wc-icon-before
andwc-icon-after
and icon classes as listed in HtmlClassProperties.