Skip to content

Handling user input

Mark Reeves edited this page Jan 4, 2018 · 3 revisions

The WComponents library includes a large range of components to obtain user input. The various components may function very differently from each other when interacted with by the user, but all provide a similar developer API.

Common developer functions include:

  • reading and modifying input values;
  • limiting the data which can be entered;
  • disabling components; and
  • field validation.

Reading and modifying input values

One of the simplest input components is a text input. The WComponent for this is the "WTextField". Part of the WTextField API contains methods to access or modify the text inside the text input.

By default WTextField displays as an empty field with no text. Developers can programmatically set the default text which is displayed by default to all users of the application. This text is used when the user has not entered any text themselves.

public String getText()
public void setText(final String text)

Any text entered by the user will be stored in the component's model once a request is made to the server. The user-specific text will then be displayed instead of the default text. User text can also be get/set using the getText/setText methods. For getText, the default text will be returned if the user has not entered any text.

The AbstractInput class is the superclass of all input components and offers a set of methods which can be used to query all components. For example, the getData and setData methods operate on WTextField in the same way as getText/setText but are not type-safe.

public Object getData()
public void setData(Object data)

Limiting the data which can be entered

Some components can limit the data which can be entered by the user. Using the WTextField as an example again, developers may wish to limit the amount of text which a user can enter. The WTextField API includes the following methods to limit the length of text which can be entered into the text field.

public int getMaxLength()
public void setMaxLength(int maxlength)

Another common type of restriction is that the user is required to pick one or more items from a list of possible values. The WDropdown component is an example of one of these which lets the user pick a single item from a list of allowable values. Developers can specify the list of available options when creating a WDropdown or use the empty constructor and set the options later.

public WDropdown()
public WDropdown(Object[] options)
public WDropdown(List options)
public WDropdown(Object table)

After construction developers can access or modify the list of allowed options using any of the following methods.

public List<?> getOptions()

public void setOptions(List options)
public void setOptions(Object[] options)

Disabling components

Most applications enforce a user workflow and prevent the user interacting with undesired sections of the application by presenting certain sections of the application in a disabled state or not presenting them to the user at all. There are four ways of stopping the user interacting with components each of which have different impacts on performance and usability:

  1. marking components as invisible;
  2. marking components as hidden;
  3. marking components as disabled; and
  4. marking components as read-only.

Invisible components

Individual components or sections of the UI can be made invisible. Invisible components are excluded from request processing on the server and will not be sent to the client.

public boolean isVisible()
public void setVisible(boolean visible)

Hidden components

Hidden components are included in request processing on the server and are sent to the client. They are not initially visible to the user but can be made visible client-side by using the WSubordinateControl component. For most components the hidden state can only be set by a WSubordinateControl.

public boolean isHidden()
public void setHidden(boolean hidden)

Disabled components

Input components can also be disabled. This is useful for indicating to the user which options are not interactive in the current context. Making a component disabled changes the component's visual appearance on the client and will prevent its value from being changed. It is possible to enable/disable components on the client using the WSubordinateControl component.

public boolean isDisabled()
public void setDisabled(boolean disabled)

Read-only components

Read-only components are intended for use where the user is viewing information which can not be changed. The primary use of this feature is for applications which use review screens to reuse large chunks of UI by just marking an entire branch of WComponents read-only.

public boolean isReadOnly()
public void setReadOnly(boolean readOnly)

Field validation

Field validation is performed server-side to enhance application security. There may be limited support in themes for improving the user experience by providing pre-submission validation. This does not replace server-side validation.

The simplest type of validation provided by WComponents is whether a field is mandatory and therefore must have a value entered by the user. All input components (which extend from AbstractInput) have the following methods available:

public void setMandatory(boolean mandatory)
public void setMandatory(boolean mandatory, String errorMessage)

public boolean isMandatory()

For more complex validation developers can create arbitrary reusable validators by implementing the FieldValidator interface. The field validators are then attached to input components using the component's addValidator method.

public void addValidator(FieldValidator validator)

Another way to implement validation is to override WComponent's validateComponent method. This method works for all component types not just input components. Overriding this method is the best approach when applications require cross-field validation. The example below shows a validateComponent implementation for a class which contains two text fields: one of which must have a value entered. A WMessages message box is used to display messages to the user and a validatingAction is used to trigger validation.

import java.util.List;

import com.github.bordertech.wcomponents.validation.Diagnostic;
import com.github.bordertech.wcomponents.validation.DiagnosticImpl;
import com.github.bordertech.wcomponents.ActionEvent;
import com.github.bordertech.wcomponents.UIContext;
import com.github.bordertech.wcomponents.WApplication;
import com.github.bordertech.wcomponents.WButton;
import com.github.bordertech.wcomponents.WTextField;
import com.github.bordertech.wcomponents.WMessages;
import com.github.bordertech.wcomponents.validation.ValidatingAction;

public class MyValidatingComponent extends WApplication {
   private final WTextField field1 = new WTextField();
   private final WTextField field2 = new WTextField();

   public MyValidatingComponent() {
      final WMessages messageBox = new WMessages();
      add(messageBox);

      WFieldLayout fieldLayout = new WFieldLayout();
      add(fieldLayout);
      fieldLayout.addField("Field 1", field1);
      fieldLayout.addField("Field 2", field2);

      WButton submitButton = new WButton("Submit");
      add(submitButton);

      submitButton.setAction(new ValidatingAction(messageBox.getValidationErrors(), this) {
         public void executeOnError(ActionEvent event, List diags) {
             // Any additional error handling can go here
             super.executeOnError(event, diags);
         }

         public void executeOnValid(ActionEvent event) {
             messageBox.success("Validation passed!");
         }
      });
   }

   protected void validateComponent(List<Diagnostic> diags) {
      if (field1.isEmpty() && field2.isEmpty()) {
         String message = "Either field 1 or field 2 must be entered.";
         Diagnostic diag = new DiagnosticImpl(field1, null, message, Diagnostic.ERROR);
         diags.add(diag);
      }
   }
}

Note that validation does not occur automatically: it must be invoked when the application deems it appropriate. The easiest way to invoke validation is by attaching an extension of ValidatingAction to a component rather than Action. If necessary validation can be also be invoked by manually calling WComponent's validate method. This will validate the component and any descendent components underneath it but will not automatically display any error messages or halt processing of actions.

public void validate(List<Diagnostic> diags)
Clone this wiki locally