How to create a form and validate it

Some ifw2 terms:

  • Forms: contains actions, fields and strokes.

    There can be more than one per Flow.

    Can be a multi-part form if used to upload files.

    Not multi-part forms can be nested, this greatly simplifies rendering decomposition.

  • Fields: ifw2 wrappers to normal html form input fields.
  • Actions: java objects used to encapsulate server-side or client-side code executed upon user interaction with the ui.
  • Strokes: java objects describing what can trigger an action, they can be used instead of "normal" ifw2 tags. (tags are used in jsp code while strokes in java code).
  • Validators: java object encapsulating server-side java code used to check fields or groups of fields content.

    They are also usable to update fields content when other fields changes.


First you have to choose between three default implementations of the IForm interface which are:

  • ActionsForm: It cannot have fields but only actions.
  • Form: Full function form with actions and fields.
  • PojoForm: Extends the Form class with fields directly binded to pojo bean-properties.

Then you have to make the form accessible by your ABndsFlow or BndsFlow, ie. register the form in case of a BndsFlow.

  ...
  public class AskForVersionLblDlg extends BndsFlow {
    private final Form   ivForm;
    ... 
    public AskForVersionLblDlg() {
      super(new JSPRenderer("/WEB-INF/jsp/dyna/ent/AskForVersionLbl.jsp"));
      ivForm = new Form();
      registerForm("form", ivForm);
      ...

Register any field you need choosing between provided IField implementations:

  • SelectField: to be used with the ifw2:bnd-select tag.
  • TextField: to be used with tags ifw2:bnd-textarea, ifw2:bnd-text and bnd-radio-group.
  • FormattedTextField: same as TextField but with an IFormatter used to convert and format the string, common used formatters are DateFormatter, NumberFormatter and EnumFormatter.
  • CheckboxField: to be used with the ifw2:bnd-checkbox.
  • PojoField: only a container for java objects, useful to handle objects lookup.

And set any property or constraint you require.

If the form is a PojoForm and the field is binded to a pojo-property then some constraints are "automatically" discovered by looking at the javax.persistence.Column annotation of the get method, if any.

      ...
      ivForm.registerField("tagLabel", 
          new TextField().setMaxLength(20).setMandatory(true).setLabel("Tag label"));
      ...

Register any required actions.

There are three types of actions:

  • IFormAction: generic server-side form actions, they can be triggered by buttons (ifw2:bnd-submit), by links (<ifw2:bnd-a), by keys/mouse gestures (ifw2:bnd-key-action and ifw2:bnd-mouse-action) or by a timer (ifw2:bnd-refresh-action).

    Can switch the flow state on execution.

  • IClientSideAction: client-side actions, same triggers as IFormAction but executes java-script code on the client browser side.
  • IFieldAction: server-side action binded to a form field.

    They can be triggered by keys/mouse gestures or by a timer.

    Cannot switch the flow state on execution

    For a sample usage see net.infordata.ifw2.web.form.CalendarAction.

In this example, since the flow will be used as a dialog we register two form actions, one to cancel and one to confirm the inputed data, each of them will cause a state switch on the flow which will, in turn, causes the dialog to close since new states are IFlowEndState.

For another example see: How to open a modal dialog.

      ...
      registerFlowState(new FlowState("one"), true);  // The beginning flow state 
      registerFlowState(DialogResultEnum.CANCEL);  // Predefined IFW2 IFlowEndState
      registerFlowState(DialogResultEnum.OK);
      ...
      // DialogResultAction is a predefined form action which will switch the flow
      // to the given state
      ivForm
      .registerAction("cancel", 
          new DialogResultAction(DialogResultEnum.CANCEL))  
      .registerAction("ok", 
          new DialogResultAction(DialogResultEnum.OK) {
            private static final long serialVersionUID = 1L;
            @Override
            public boolean onBeforeExecute(ActionInfo action) {
              return ivForm.validate(null);  // validate the form before proceeding
            }
      });
      ...

Register any stroke you require.

A Stroke is a way to define action triggers directly into your java code without using jsp tags.

      ...
      ivForm.getStrokes()
      .registerStroke(new Stroke("ok")), "okAction")  // the ok buttom
      .registerStroke(new Stroke(KeyEnum.ENTER, true), "okAction");  // the enter key triggers the okAction
      ivForm.getStrokes()
      .registerStroke(new Stroke("cancel"), "cancelAction")
      .registerStroke(new Stroke(KeyEnum.ESC, true), "cancelAction");
      ...

Add any IFormValidator you need (better to use IFormValidator2 or APojoFormValidator if you are dealing with a PojoForm).

      ...
      ivForm.addValidator(new Validator());  
      ivForm.validate(null);  // trigger a validation immediately
      ...

Implement your validators, in this example it is an inner class.

  ...
  private static final String[] FIELDS = new String[] { "tagLabel" };

  private static enum MTPV implements IMessageToken { UNIVOCITY };
  
  protected class Validator implements IFormValidator2 {

    private static final long serialVersionUID = 1L;
    
    @Override
    public String[] getFieldNames() {
      return FIELDS;
    }

    @Override
    public boolean isApplicable() {
      return true;
    }
    
    ...
    
    @Override
    public void validate(IFormView form, String... fieldsToValidate) {
      AFormField<String> labelField = form.getField(String.class, "tagLabel");  
      //
      String value = labelField.getValue();
      if (value == null)
        return;
      EntityManager em = JpaUtil.getCurrentEntityManager();
      EntityTransaction trans = em.getTransaction();
      trans.begin();
      try {
        Query query = em.createQuery(
            "select xx.IId from DynaEntity xx " +
            "  where xx.tagOf=:dynaEntity and" +
            "        xx.tagLabel=:tagLabel")
          .setParameter("dynaEntity", ivDynaEntity)
          .setParameter("tagLabel", value);
        query
        .setMaxResults(1)
        .setHint("org.hibernate.readOnly", true);
        List<?> res = query.getResultList();
        if (res.size() > 0) {
          labelField.setMessage(MTPV.UNIVOCITY, new SimpleMessage("Duplicate value"));
        }
      }
      finally {
        if (trans.isActive())
          trans.rollback();
      }
    }
  }
  ...

Finally write your jsp (/WEB-INF/jsp/dyna/ent/AskForVersionLbl.jsp).

Notice the usage of the ifw2:bnd-action-group tag which must surround any action triggering tags but ifw2:bnd-a. It is used also to place action triggers defined in java code via strokes.

  <%@ page language="java"%>

  <%@ taglib uri="http://www.infordata.net/taglibs/ifw2" prefix="ifw2"%>

  ...
  <ifw2:bnd-form bind="form">
  <table>
    ...
    <tr>
      <td><ifw2:bnd-label bind="tagLabel"/>:</td>
      <td>
        <ifw2:bnd-text size="20" bind="tagLabel" focused="1"/>
      </td>
    </tr>
    <tr>
      <td colspan="2" valign="bottom" align="left">
          <ifw2:bnd-action-group id="a" keepFormStrokes="true">
          </ifw2:bnd-action-group>
      </td>
    </tr>
  </table>
  </ifw2:bnd-form>
  ...