5. Reading data from a form

Since we need to handle input from the user we have a form on the web page, with an entry and a submit button. This is reflected in the Guess element definition by the submission tag:

Example 3.7. Adding a submission to the guess element

<element implementation="tutorial.numberguess.Guess">
  <input name="gameid"/>

  <submission name="performGuess">
    <param name="guess">
      <default>-1</default>
    </param>
  </submission>

  <exit name="start"/>
  <exit name="success"/>

  <output name="gameid"/>
</element>

Here, we have defined one submission parameter, namely the number that the user guessed. Submissions always refer back to the original element. This centralizes all the handling of a submission in the same element, instead of having one page for showing the form and another one that deals with the submitted data.

Since the form display and data processing is done in the same element, it's easy to just show the form again if some data is missing or invalid, without having to ask the user to go back to the previous page to fill out the rest.

We also need to add a bit of code to the template to handle the submission form:

Example 3.8. The guess template with a form

<form action="[!V 'SUBMISSION:FORM:performGuess'/]" method="post">
  <!--V 'SUBMISSION:PARAMS:performGuess'/-->
  <input type="text" name="guess" value="[!V 'PARAM:guess'][!/V]" /><br />
  <input type="submit" value="Guess" /><br />
</form>

The action is set to a special value: SUBMISSION:FORM:performGuess. RIFE replaces this value with the correct URL, in this case the URL that corresponds to the GUESS element. The last part of this special value refers to the name of the submission that you declared earlier in the element XML definition.

The value of the text input HTML tag is set to the PARAM:guess value. This again corresponds to the guess parameter of your submission definition. This value is automatically replaced by the last value of the parameter and allows the user to always see the last guess that was made. Note that we use a a longer value tag here and we'll explain its use in detail later. All you have to know now is that when no guess parameter is available, the value will be replaced with an empty string and thus show up as an empty field to the user.

Warning

You always have to use SUBMISSION:FORM:name together with SUBMISSION:PARAMS:name. RIFE will warn you about this, but it's always good to know beforehand.

Values with a prefix like SUBMISSION: are treated specially by RIFE. Here, for instance, the form action and parameters are set up. There are other prefixes such as EXIT: and CONFIG: as we will see later on. These tags are called filtered value tags since RIFE automatically filters them out and replaces them with special content that's related to the application.

When the page is entered, the element needs to check if a submission exists, and if so, handle it. The check is done through the hasSubmission method and values are fetched with the various methods that start with getParameter. To get an integer value, getParameterInt is used, and so on. The complete list of methods can be found in the API reference documentation, under the class com.uwyn.rife.engine.Element.

Example 3.9. Java code for the Guess element

package tutorial.numberguess;

import com.uwyn.rife.engine.Element;
import com.uwyn.rife.template.Template;
import tutorial.numberguess.backend.Contest;
import tutorial.numberguess.backend.Game;

public class Guess extends Element
{
  private Template mTemplate = null;

  private void handleGuess(Game game)
  {
    int guess = getParameterInt("guess", -1);
    if (guess < 0 || guess > 100)
    {
      mTemplate.setBlock("warning", "invalid");
      return;
    }

    game.increaseGuesses();

    if (game.getAnswer() < guess)
    {
      mTemplate.setBlock("indication", "lower");
    }
    else if (game.getAnswer() > guess)
    {
      mTemplate.setBlock("indication", "higher");
    }
    else
    {
      setOutput("gameid", getInput("gameid"));
      exit("success");
    }
  }

  public void processElement()
  {
    Game game = Contest.getGame(getInput("gameid"));
    if (null == game)
    {
      exit("start");
    }

    mTemplate = getHtmlTemplate("guess");

    if (hasSubmission("performGuess"))
    {
      handleGuess(game);
    }

    print(mTemplate);
  }
}

In Example 3.9, “Java code for the Guess element” we see quite a few interesting parts. Let's start with the call to exit in processElement. This instructs RIFE to activate the flow link that's connected to the start exit. No further processing is done in the element, it will immediately be exited and the logic will proceed with the element that's being pointed to by the flow link. In this particular example, it causes the start page to be shown when no active game could be found.

If a game was successfully retrieved, a check is done to see if the request contains the submission named "perform_guess". If it does, handleGuess is called to see if the user's guess is correct. If it is, the exit named "success" is triggered and the element connected to this exit will handle the output.

If no submission was found, the default template will be displayed, which asks the user to enter a guess.