The ADF Faces inputText component

The ADF Faces library contains many JSF components. One of the most common used components is the af:inputText. In the JHeadstart it is the default type for most items. According to the description it will be rendered as an HTML input text element and thus be able to handle user input. However, you must be aware of a huge caveat, that it does not always render as an HTML input text element, but that it can be rendered as plain text too. In this post I will describe under which conditions this occurs and present a solution if you don’t want that behaviour.
....

When an af:inputText is considered read-only it is rendered as plain-text instead of an HTML input text.
You can easily try it : <af:inputText label="default item" value="myValue"/> renders as inputtext, while <af:inputText label="readonly item" readOnly="true" value="myValue"/> renders as plain text. You even don’t need to run the page, you can already see it in the JDeveloper design editor :

Default inputtext vs. read-only 

Off course, this is the same for a ‘numeric’ value : <af:inputText label="some ‘numeric’ value" value="5000"/>

But this not the whole story because the value can be the result of an EL-expression. But all the simple EL-expressions, like #{5000} or #{2000 + 3000} are rendered as plain text. But now you only see the effect when you’re running the page. In the design editor they still look like inputtext.Off course, this is not a great example, how often are you doing these kind of calculations. It becomes more interesting when we retrieve the value from some Java component.

So we make a very simple java class Person with an id (long) and a name (String) attribute with getters and setters and give them for demonstration purposes the values 12345L and "Pietje Puk". Then we add it as a managed bean to our application by configuring the faces-config.xml file:

<managed-bean>
  <managed-bean-name>person</managed-bean-name>
  <managed-bean-class>nl.amis.demo.jsf.Person</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

We can now use an EL-expression to retrieve the value from these bean’s attributes, like <af:inputText label="id" value="#{person.id}"/> and <af:inputText label="name" value="#{person.name}"/>. Notice that the design editor already shows you the value in the managed bean. And now comes the trick: remove the setter of the id attribute and …..

…the inputtext is now rendered as plain text instead of an inputtext. When you use ADF BC as the persistence layer, the updatable propery of the ViewObject and/or EntityObject is also responsible for this rendering behaviour, although in these cases the setter is still available. So obviously, the renderer is quite smart (?!), the result is not only the result of the component’s properties but also of the underlying object.
Although this sometimes makes perfect sense, it can also make your user-interface quite messy, especially when items have an horizontal layout or when they are used for summary purposes. In these cases a disabled inputText would be much more appropriate. Normally you would use the disabled property as <af:inputText label="disabled item" disabled="true" value="myValue"/> or with an EL-expression <af:inputText label="name" value="#{person.name}" disabled="#{person.id == 12345}"/>.

The ADF Faces inputText component
 
But that has no effect on a read-only value, it’s still rendered as plain text.

So far, we’ve seen that the af:inputText can either be rendered as an HTML input text element or as plain text and that it depends on the readonly-ness of its value. But wait, there is more… the rendering is also dependent on the surrounding conponent. A form element must always be placed inside a form (hence the name) and this applies to the af:inputText component too. You can use the standard JSF form (h:form) to place the af:inputText components. The result may look like this :

The ADF Faces inputText component
 
The result is not pretty and you’ll have a touch job making it better looking. If you like these challenges go ahead, but I prefer the use of a more feature rich component like the ADF Faces af:panelForm component. Now it looks like this :

The ADF Faces inputText component
This is often much more appreciated and may be suitable in most places. But what if you don’t want the read-only items to be formatted as plain text but like a disabled item. As we’ve seen, we cannot use the af:inputText. Now does the standard jsf library come in handy, because its inputText always renders as an HTML input text element, read-only or not. In all the demonstrated cases, the result is always an input text element. You can use the readonly and disabled properties to make sure the data cannot be manipulated. However, there are some drawbacks :

  1. It has no label property
  2. The items are placed next to each other instead of underneath each other.
  3. It’s not alligned by the af:panelForm.
  4. It is not as feature rich.
  5. You cannot use partial triggers

By the way, the af:inputText component has a ‘simple’ property that disables the label and doesn’t use the allignment too.

To add a label to the item and to make sure it can be properly alligned we have to combine some components. We’ll use the adf faces af:panelLabelAndMessage component and place a jsf inputText inside it :

<af:panelForm width="25%">
    <af:panelLabelAndMessage for="id1" label="id">
      <h:inputText id="id2" value="#{person.id}" readonly="true"/>
    </af:panelLabelAndMessage>
    <af:inputText label="id" value="#{person.id}"/>
</af:panelForm>

This is the result (although it looks editable, believe me you cannot):

The ADF Faces inputText component
 
It’s interesting to see that the behaviour of this combined component is the same as the af:inputText. It can be alligned properly and is almost has the same properties as the af:inputText. I won’t go into detail of how you can make it even prettier, using tips, the shortDesc, the size or disabled properties, you can find out yourself.

Although the af:inputText
and the h:inputText components are very similar, it really annoys me that some properties are slightly different named and that the name in the JDeveloper property inspector is not equal to the actual property name:

standard jsf adf faces
size columns
readonly readOnly
maxlength maximumLength
style inlineStyle

 

Since we use JHeadstart to generate out adf faces application, we created a velocity template, jsfFormTextInput.vm for this component.

<af:panelLabelAndMessage #ITEM_PROMPT_IN_FORM()  #ITEM_HINT()
                         #ITEM_RENDERED_IN_FORM() #ITEM_PARTIAL_TRIGGERS()
                         for="$JHS.current.item.bindingName >
    <h:inputText #ITEM_ID_IN_FORM() #ITEM_VALUE_IN_FORM()
                 #ITEM_RENDERED_IN_FORM() #ITEM_DISABLED_IN_FORM()
                 #ITEM_REQUIRED_IN_FORM() #DEPENDS_ON_ITEM_PROPS()
                 readonly="$JHS.current.item.readOnlyInForm"
                 size="$JHS.current.item.displayWidth"
                 maxlength="$JHS.current.item.maximumLength"
                 style="text-align:right;" >
    </h:inputText>
</af:panelLabelAndMessage>

As you see, the af:inputText properties have been replaced with the corresponding h:inputText properties and some of them have been moved to the panelLabelAndMessage component and all of the original properties could be fitted within this combined component. Notice that the only way to right-align text in an input text is with the use of a style sheet.
Off course, we didn’t stop here. For reusability purposes we created macro’s for the new properties and put them in the JHeadstart common_items.vm template. Don’t forget to add them again after a JHeadstart upgrade, although you can’t generate without them anyhow ;-).
For demonstartion purposes I only show the macro that generates the size property :

#macro (JSFITEM_SIZE)
  #JHS_PROP("size" $JHS.current.item.displayWidth)
#end

You now have an input component with the same functionality as an af:inputText, but one that is always rendered as an input text element and not, in some cases, as plain text. You can pimp it as you like with outputlabels, converters, validators etc. just as you could do with an af:inputText component. By the way, next version of JHeadstart will include the validator (which is a property in the application definition file) in its templates and you don’t need to add it to your own.

Resources

ADF faces core tag library
JHeadstart@OTN
 

One Response

  1. Prasad November 5, 2009