Showing posts with label input. Show all posts
Showing posts with label input. Show all posts

Monday, May 18, 2009

JSF input - empty value converted to Zero

When running a JSF application under Tomcat, you might encounter a weird case in which an empty value of a field bidden with numeric property (like Integer) is converted to zero instead of remaining "null".

Consider the following case, in which text field is used to input Integer value:

<h:inputText id="myInput" value="#{myBean.myInteger}" converter="IntegerConverter" />

And the bean holding the value:

package com.bashan.blog.jsf;
public class MyBean {
  private Integer myInteger;
  public Integer getMyInteger() {
    return myInteger;
  }
  public void setMyInteger(Integer myInteger) {
    this.myInteger = myInteger;
  }
}
Apparently, Tomcat is coercing “null” values to zeroes. This behavior can be disabled by setting the following JVM parameter to "false":
-Dorg.apache.el.parser.COERCE_TO_ZERO=false

By default the “true” value is used. By setting this value to “false” Tomcat will no longer try to coerce value expressions.

You can also set this parameter in Java code. This may be a better idea, if you don’t want to remember to set this parameter on each new environment you deploy your web application. Here is how it can be done:

System.getProperties().put("org.apache.el.parser.COERCE_TO_ZERO", "false");

You can run this code when your server first loads in some initialization Servlet.

If I recall correct, this behavior was changed sometime along the development of Tomcat. That means you can experience different behaviors on different environments of Tomcat. For example, Production environment behaves differently from Development environment, since there are 2 distinct versions of Tomcat. This may cause a bit confusion, when trying to identify the problem.

Sunday, April 19, 2009

Inputting only numbers using Java Script and HTML

The basic input text field of HTML is very limited when it comes numeric data. There are times in which a better user experience is needed.
In order to generate a better user experience, 2 main features can be easily added to the input text field by using JavaScript:
  • Allow user to input only numeric data. That means that any character other than numbers dots or commas is not allowed. This feature prevents from the user to entering undesired data to the field.
  • Show data in a formatted manner when field is not edited. That means that when field lost focus, its contents are shown with commas or dots. That makes the numeric data on the text field to be more readable.
Note, that we also would like the text to be formatted according to a specific Locale. That means that we want to use decimal separator and grouping separator to be according to our demands. There are countries and cultures in which the decimal separator is comma and some other countries in which decimal separator is dot. The same applies to grouping separator.
In order to achieve our 2 goals we will build 3 java script functions. Each function will be assigned to a specific JavaScript event.
  • onkeypress: This event is activated whenever a key is being pressed when the cursor is in the text field. A function that returns "false" on this event cancels the event and thus prevent from the pressed character to be updated on the text field. We will assign to this even a function named: numbersOnly. This function receives 4 parameters:
    • field: The text field that called the function.
    • e: The onkeypress event.
    • isDec: Indicate that we would like the input to be decimal and not only integer.
    • decimalSeperator: The character used as a decimal separator (probably “.” or “,”).
    In return this function will return true whenever the pressed character is allowed to be inputted by the user or false if character is not allowed to be inputted.
  • onfocus: This event is activated when the text field receives focus. That means, when we are entering to the text field. This event will be assigned with a function named: plainNumber. This function takes the numeric data in the text field and converts it to a plain number, meaning, any numeric formatted data containing dots or command will be converted to a plain number ready to be edited. This function has 2 parameters:
    • field: The text field field that called the function.
    • decimalSeperator: The character used as a decimal separator (probably “.” or “,”).
  • onblur: This event is activated when the field loses focus. That means when we are entering the field by moving to another element on the page. This event will be assinged with a function named: formattedNumber. This function converts the plain numeric data on the text field to a formatted data containing grouping separators. This function has 3 parameters:
    • field: The text field field that called the function.
    • decimalSeperator: The character used as a decimal separator (probably “.” or “,”).
    • groupingSeperator: The character used as a grouping separator (probably “.” or “,”).

I made an example showing a text field utilizing the 3 events to create the described behavior. The example contains a simple HTML page containing the JavaScript methods and a simple text field. The JavaScript code used in this example is not state of the art, but working fine on both FireFox and Explorer. This code can be further refined by encapsulating all the behavior to a single static JavaScript class.

Here is the example code showing input numbers only of an Integer number:

<html>
 <head>
  <title> JavaScript Input Example </title>
 </head>
 <body>
<script>
function numbersOnly(field, e, isDec, decimalSeperator)
{
  var key;
  var keychar;
if (window.event)
   key = window.event.keyCode;
else if (e)
   key = e.which;
else
   return true;
  keychar = String.fromCharCode(key);
// control keys
  if ((key == null) || (key == 0) || (key == 8) ||
      (key == 9) || (key == 13) || (key == 27) || (key == 39) /*|| (key == 37)*/)
  {
    return true;
  }
  else if ((("0123456789").indexOf(keychar) > -1) ||
    (isDec && (keychar == decimalSeperator) && (field.value.indexOf(decimalSeperator) < 0)))
  {
    return true;
  }
 return false;
}
function formattedNumber(field, decimalSeperator, groupingSeperator)
{
    field.value = addGroupingSeperator(field.value, decimalSeperator, groupingSeperator);
}
function plainNumber(field, decimalSeperator)
{
    field.value = field.value.replace(
        new RegExp("[^0123456789" + decimalSeperator + "" + "]", 'g'), "");
}
function addGroupingSeperator(nStr, decimalSeperator, groupingSeperator)
{
    nStr += '';    
    x = nStr.split(decimalSeperator);
    x1 = x[0];
    x2 = x.length > 1 ? decimalSeperator + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + groupingSeperator + '$2');
    }
    return x1 + x2;
}
</script>
    <input id="inputInteger" name="inputInteger" maxLength="7"
       onfocus="plainNumber(this, '.');"
       onblur="formattedNumber(this, '.', ',')"
       onkeypress="return numbersOnly(this, event, false, '.')">
 </body>
</html>
Note that the data of the decimal and grouping separator can be taken from your programming language and assigned dynamically according to the specific user Locale information.