fc.web.simpleforms
Class State

java.lang.Object
  extended by fc.web.simpleforms.State

public final class State
extends Object

Helps maintain form state. Form state needs to be maintained when a form is submitted but needs to be redisplayed to the user because of errors or incomplete fields.

For example:

<input name=foo type='text' value='[= State.text(req, "foo")]'> 
Often we need to set default/initial values (say from a database) for pre-filling a form before it's shown to the user (for example, when the user is editing some information that already exists in the database). In the simple form API, this is done via invoking the set(req, field_name, field_value) method, which sets the initial value of the field in the specified HttpServletRequest object (mimicking as if the user had entered those values and submitted the form). Since various widgets maintain state by retrieveing these values from the HttpServletRequest, these values will be shown to the user. For example:
String initial_value = databaseQuery.getUserName(); //for example
State.set(req, "foo", initial_value);

...later in the page...
//this will show the initial value set above and also maintain state
//when the user changes the value and submits the form
<input name=foo type='text' value='[= State.text(req, "foo")]'> 


Constructor Summary
State()
           
 
Method Summary
static String checkbox(javax.servlet.http.HttpServletRequest req, String name)
          Returns the checked state of the submitted checkbox.
static String checkboxgroup(javax.servlet.http.HttpServletRequest req, String name, String value)
          Returns the submitted state of the specified check box which is part of a checkbox group (multiple check buttons with the same name).
static void clear(javax.servlet.http.HttpServletRequest req)
          The servlet api is written by retarded monkeys smoking crack....which is why there is no way to modify/remove/change/clear the parameters in the servlet request (the parameters map is read-only) ..which leads to all sort of problems in html form processing.
static String disabled(javax.servlet.http.HttpServletRequest req, String name)
          Convenience method.
static String escapedHidden(javax.servlet.http.HttpServletRequest req, String name)
          Convenience method that returns: HTMLUtil.quoteToEntity(hidden(req, name)); Useful for setting arbitrary values in the value="..." part of a hidden field.
static String escapedPassword(javax.servlet.http.HttpServletRequest req, String name)
          Convenience method that returns: HTMLUtil.quoteToEntity(password (req, name)); Useful for setting arbitrary values in the value="..." part of a password field.
static String escapedText(javax.servlet.http.HttpServletRequest req, String name)
          Convenience method that returns: HTMLUtil.quoteToEntity(text(req, name)); Useful for setting arbitrary values in the value="..." part of a text field.
static boolean getDisabled(javax.servlet.http.HttpServletRequest req, String name)
          Returns true if the specified field was marked as disabled.
static String hidden(javax.servlet.http.HttpServletRequest req, String name)
          Returns the value of the submitted hidden field or an empty string if no value was submitted (this can happen if the user hacked/removed this value manually).
static String makeOptions(javax.servlet.http.HttpServletRequest req, String selectName, List optionList)
          Convenience method that creates a list of select options that maintain form state.
static void makeOptions(PrintWriter out, javax.servlet.http.HttpServletRequest req, String selectName, List optionList)
          Convenience method that creates a list of select options that maintain form state.
static String password(javax.servlet.http.HttpServletRequest req, String name)
          Returns the value of the submitted password (or an empty string if no value was submitted).
static String radio(javax.servlet.http.HttpServletRequest req, String name)
          Calls radio(req, name, false)
static String radio(javax.servlet.http.HttpServletRequest req, String name, boolean selected)
          Returns the submitted state of the submitted radio box.
static String radiogroup(javax.servlet.http.HttpServletRequest req, String name, String value)
          Returns the submitted state of the specified radio box which is part of a radio group (multiple radio buttons with the same name).
static String select(javax.servlet.http.HttpServletRequest req, String selectName, String optionVal)
          Returns the state of the submitted select.
static void set(javax.servlet.http.HttpServletRequest req, String name, String value)
          Sets the value of the form element with the specified name.
static void setDisabled(javax.servlet.http.HttpServletRequest req, String name)
          Convenience method that marks the specified field as disabled.
static String text(javax.servlet.http.HttpServletRequest req, String name)
          Returns the value of the submitted text area (or an empty string if no value was submitted).
static String textarea(javax.servlet.http.HttpServletRequest req, String name)
          Returns the value of the submitted text area (or an empty string if no value was submitted).
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

State

public State()
Method Detail

text

public static final String text(javax.servlet.http.HttpServletRequest req,
                                String name)
Returns the value of the submitted text area (or an empty string if no value was submitted). Example:
<input type=text name=foo value='[=State.text(req, "foo")]'>


textarea

public static final String textarea(javax.servlet.http.HttpServletRequest req,
                                    String name)
Returns the value of the submitted text area (or an empty string if no value was submitted). The returned value is trimmed of all leading and trailing spaces.

The returned value replicates what the user entered and is not url encoded. This is good when maintaining state.

Of course, when saving this out to the database, we should either strip naughty tags or save it as url encoded text. (otherwise, the door to cross-site scripting hacks is wide open). That's an orthogonal issue to maintaining form state via this method. Example:

<textarea name=foo>
[=State.textarea(req, "foo")]
</textarea>


password

public static final String password(javax.servlet.http.HttpServletRequest req,
                                    String name)
Returns the value of the submitted password (or an empty string if no value was submitted). Example:
<input type=password name=foo value='[=State.password(req, "foo")]'>


radio

public static final String radio(javax.servlet.http.HttpServletRequest req,
                                 String name,
                                 boolean selected)
Returns the submitted state of the submitted radio box. This radio box should not be part of a radio group (multiple radio buttons with the same name). For radio groups use the radiogroup method. Example:
<input type=radio name=foo value='somevalue' [=State.radio(req, "foo")]>
Note: For radio boxes, the state maintainence value is the presence/absence of the checked attribute. The value returned by this method will be either an empty string or checked. This should not be assigned to the 'value' attribute (if present) of the radiobox. Rather, it should be a stand-alone attribute.

Parameters:
name - the name of the radio element
selected - true to select this radio box initially (the first time the form is shown to the user), false otherwise.

radio

public static final String radio(javax.servlet.http.HttpServletRequest req,
                                 String name)
Calls radio(req, name, false)


radiogroup

public static final String radiogroup(javax.servlet.http.HttpServletRequest req,
                                      String name,
                                      String value)
Returns the submitted state of the specified radio box which is part of a radio group (multiple radio buttons with the same name). For non-group radio boxes, use the radio method instead. Example:
Good:
<input type=radio name=foo value='somevalue1' [=State.radiogroup(req, "foo", "somevalue1")]>
<input type=radio name=foo value='somevalue2' [=State.radiogroup(req, "foo", "somevalue2")]>

Don't do this
<input type=radio name=foo [=State.radiogroup(req, "foo", "on")]>
This method takes a value parameter that specifies the value associated with this particular radio box in the radio group. Radios with no specific value are submitted with the value "on" (case-insensitive) by the browser. (as seen in the second example above). This method requires that each radio in the radiogroup have a unique and specified value tag.

Note: For radio boxes, the state maintainence value is the presence/absence of the checked attribute. The value returned by this method will be either an empty string or checked. This should not be assigned to the 'value' attribute (if present) of the radiobox. Rather, it should be a stand-alone attribute.


checkbox

public static final String checkbox(javax.servlet.http.HttpServletRequest req,
                                    String name)
Returns the checked state of the submitted checkbox. This radio box should not be part of a radio group (multiple checkboxes with the same name). For radio groups use the checkboxgroup method. Example:
<input type=checkbox name=foo value='somevalue' [=State.checkbox(req, "foo")]>
Note: For check boxes, the state maintainence value is the presence/absence of the checked attribute. The value returned by this method will be either an empty string or checked. This should not be assigned to the 'value' attribute (if present) of checkbox. Rather, it should be a stand-alone attribute as shown above.

Parameters:
name - the name of the radio element
selected - true to select this checkbox box initially (the first time the form is shown to the user), false otherwise.

checkboxgroup

public static final String checkboxgroup(javax.servlet.http.HttpServletRequest req,
                                         String name,
                                         String value)
Returns the submitted state of the specified check box which is part of a checkbox group (multiple check buttons with the same name). For non-group check boxes, use the checkbox method instead.

Note: Checkboxes with no specific value are submitted with the value "on" (case-insensitive) by the browser (as seen in the second and third example below). Example:


Good:
<input type=checkbox name=foo value='somevalue1' [=State.checkboxgroup(req, "foo", "somevalue1")]>
<input type=checkbox name=foo value='somevalue2' [=State.checkboxgroup(req, "foo", "somevalue2")]>

Don't do this:
<input type=checkbox name=foo [=State.checkboxgroup(req, "foo", "on")]>
<input type=checkbox name=foo [=State.checkboxgroup(req, "foo", "on")]>
This method takes a value parameter that specifies the value of the check box in the checkbox group. This method requires that each checkbox in the group have a specified and unique value attribute.

Note: For check boxes, the state maintainence value is the presence/absence of the checked attribute. The value returned by this method will be either an empty string or checked. This should not be assigned to the 'value' attribute (if present) of the checkbox. Rather, it should be a stand-alone attribute.


hidden

public static final String hidden(javax.servlet.http.HttpServletRequest req,
                                  String name)
Returns the value of the submitted hidden field or an empty string if no value was submitted (this can happen if the user hacked/removed this value manually). Example:
<input type=hidden name=foo value='[=State.hidden(req, "foo")]'>


select

public static final String select(javax.servlet.http.HttpServletRequest req,
                                  String selectName,
                                  String optionVal)
Returns the state of the submitted select. For select options, we need to maintain whichever option(s) were selected by the user. The presence/absence of the selected attribute maintains this state.

When maintaining states for select input types:

  1. We know the select options on the server-side and write them out dynamically (or statically) on the server-side and then send the page to the client. To maintain state, we say:
    <select name=sel1>
    <option value="1" [=State.select(req, "sel1", "1")]> Option 1
    <option           [=State.select(req, "sel1", "Option 1")]> Option 1
    </select>
    
  2. We query and create select options on the client-side using ajax/js/etc (for example, if the client chooses a country, we query a database and show the states for that country via another client-side select, created dynamically). Upon submission of this form, we still need to maintain the state of this option. To do this, we need to know, on the server side, the names of any new selects that are created on the client (and/or the names of initially empty selects that are re-populated on the client). Suppose, initially we have:
    <select name=states>
    </select>
    
    On the client, we then add:
    <select name=states>
    <option> Pennsylvania (generated on client)
    </select>
    
    To maintain the state on the server for this option, we now have to say on the server-side (upon form submission):
    <select name=states>
       <option [=State.select(req, "states", "?")]>Pennsylvania (generated on client) 
    <select>
    
    But we don't know what value to put in "?" on the server-side because Pennsylvania was generated on the client. So we can do any of the following:
    1. Rerun the query on the server, get the list of states again and say, for example something like:
      [[
      if (...options were added by by client...)
          { //maintain state
          List option_list == ...create new SelectOption's here [possibly via a query]...
          out.print(" <select name=states> ");
          for (int n = 0; n < option_list.size(); n++) 
              {
              SelectOption opt = (SelectOption) option_list.get(n);
              String html = opt.getHTML();
              String val  = opt.getValue();
              out.print(" <option val=");
              our.print(val);
              if (State.select(req, "states", val)) {
                  out.print(" selected ");
                  }
              out.print(" > ");
              out.print(html);
              }
          out.print(" </select> ");
          }
      ]]
      
      But this (kind of) defeats the purpose of using ajax because we have to replicate the logic on the server.
    2. Another solution is to write out the possible values to be shown to the client as a javascript array on the page. Then the client js can show the contents of a an array depending on user choice. This saves a ajax call to the database. If we store the results of the query in a cache or a static variable, then we don't have to re-run the query every time and can simply rewrite the array from the cached query results.
    3. Another option is that when the form is submitted to the server, it sets a hidden field with the submitted value of the select. Upon recieving the page, javascript on the browser re-runs the query on the client side again and then uses the hidden field to restore the state of the select option.

    These issue only arise when select elements are being modified on the client side via Javascript.

Parameters:
req - the HttpServletRequest
selectName - the name of the select field
optionVal - the value attribute of the option. If the option has no option attribute, the html text associated with that option. Browsers do not submit leading spaces in the html text so, for example for: "<option>  Option 1", the value would be "Option 1"

makeOptions

public static void makeOptions(PrintWriter out,
                               javax.servlet.http.HttpServletRequest req,
                               String selectName,
                               List optionList)
Convenience method that creates a list of select options that maintain form state. Example:
[[
List list = (..create a list of SelectOption, possible from database lookup..)
]]
<select name=foo>
[[ makeOptions(out, req, "foo", list); ]]
</select>

Parameters:
out - destination where the options will be printed
req - the current HttpServletRequest
selectName - the name of the select field
optionsList - a list of objects of type SelectOption

makeOptions

public static String makeOptions(javax.servlet.http.HttpServletRequest req,
                                 String selectName,
                                 List optionList)
Convenience method that creates a list of select options that maintain form state. Returns the list of options as a string (rather than printing it to a printwriter as some other variants of this method do). Example:
[[
List list = (..create a list of SelectOption, possible from database lookup..)
]]
<select name=foo>
[= makeOptions(req, "foo", list); ]
</select>

Parameters:
req - the current HttpServletRequest
selectName - the name of the select field
optionsList - a list of objects of type SelectOption

set

public static final void set(javax.servlet.http.HttpServletRequest req,
                             String name,
                             String value)
Sets the value of the form element with the specified name. This method is useful to set initial values for the form. The initial values shown to the user can be different per user, for example, when the user is editing some data that already exists on the database.

This method can be invoked more than once. This is useful to set multiple values for the same field (for example, a select box with multiple selections or multiple checkboxes with the same name).

State.set(req, "checkbox1", "1.a");
State.set(req, "checkbox1", "1.b");


clear

public static final void clear(javax.servlet.http.HttpServletRequest req)
The servlet api is written by retarded monkeys smoking crack....which is why there is no way to modify/remove/change/clear the parameters in the servlet request (the parameters map is read-only) ..which leads to all sort of problems in html form processing.

This method changes the state of all fields such that methods that return state (text, textarea, radio etc) will act as if the form field had not been submitted by the user. However, any values set by the set method after invoking this method will be seen.

All this is really useful when form data has been saved and the user needs to be shown the same form, but with an empty (fresh) form state. So for example:

// At the top of a page
String field_1 = req.getParameter("field_1");
String field_2 = req.getParameter("field_2");

Errors err =  validate_and_save(field1, field2);
if (err == null) {
    State.clear(req);  //req is the HttpServletRequest object
    State.set("field_1", "enter a value"); //initial value for field_1
    }

<form>
[[ if (err != null) { err.renderFormErrors(out); } ]]
<input type=text name=field_1 value='[=State.text(req, "field_1")]'>
<input type=text name=field_2 value='[=State.text(req, "field_2")]'>
</form>
Note: redirecting the client to the form page also has the same effect (of clearing request parameters), because that forces a entirely new request object to be used on the server.


escapedText

public static final String escapedText(javax.servlet.http.HttpServletRequest req,
                                       String name)
Convenience method that returns: HTMLUtil.quoteToEntity(text(req, name)); Useful for setting arbitrary values in the value="..." part of a text field.


escapedPassword

public static final String escapedPassword(javax.servlet.http.HttpServletRequest req,
                                           String name)
Convenience method that returns: HTMLUtil.quoteToEntity(password (req, name)); Useful for setting arbitrary values in the value="..." part of a password field.


escapedHidden

public static final String escapedHidden(javax.servlet.http.HttpServletRequest req,
                                         String name)
Convenience method that returns: HTMLUtil.quoteToEntity(hidden(req, name)); Useful for setting arbitrary values in the value="..." part of a hidden field.


setDisabled

public static final void setDisabled(javax.servlet.http.HttpServletRequest req,
                                     String name)
Convenience method that marks the specified field as disabled. This value can be later retrieved while rendering the form via the getDisabled or disabled methods.


getDisabled

public static final boolean getDisabled(javax.servlet.http.HttpServletRequest req,
                                        String name)
Returns true if the specified field was marked as disabled. Example usage:
[= State.getDisabled(req, "somefield") ? "disabled" : ""]


disabled

public static final String disabled(javax.servlet.http.HttpServletRequest req,
                                    String name)
Convenience method. Instead of saying: Example usage:
[= State.getDisabled(req, "somefield") ? "disabled" : ""]
this method allows one to say:
[= State.disabled(req, "somefield")]