JHeadstart 10.1.3 – Generating InputTextHyperlink items – a generic custom generator template

One of the big new things in JHeadstart 10.1.3 for ADF Faces undoubtedly is the very rich support for custom templates. We can use custom templates to extend, complement and override the default Application Generator’s behavior. It allows us to create a tailored and more powerful application generator. Especially when we define custom templates with a generic purpose. In this article I want to demonstrate an example of such a template.

The situation is the following: Many pages developed with JHeadstart and ADF Faces will contain items that
contain URLs. The user can enter a URL in such items and submit
the value. However, I would like the contents of such an item to be treated as not just text: it
should be available as a hyperlink as well.

For example my demo-page shown below allows
users to enter requests for books to be ordered for our in-house
library. To support their request, they can enter the URL of the Book’s
Homepage. I have created a JHeadstart custom template that allows we to generate text items as text-hyperlink items : I have added a little icon
(objectImage) that allows navigation to the URL that is in the field
itself (non-read only items) and clickable url’s instead of disabled text input items for read-only items.

And for read-only items:

 

....
 

 

The page I have generated, using the custom template, looks like this in its entirety. 

 

The URL item used to be a simple input field, such as the Uitgever and Richtprijs items. In a previous post – ADF Faces: The InputTextHyperlink Component –  I have explained what the ADF Faces ‘code’ looks like needed for this change in the page. That is always the first step with creating a custom template: manually change the generated page to whatever it is you want the generator to generate.

The second step is to take the template used for generating the item as it was, create a copy of it and start applying changes. When you are just making sure that your manual changes for a specific item will be retained when regenerating the group, you can simply copy the manual changes to the custom template and be done with it. However, if you want those changes to be more generic: not specific to this item in these circumstances but applicable to various items, you will have to be more careful. All references to the item, its group and other specific details should be replaced with generic references to the Application Definition properties.

Turning specific, manual changes into a generic custom template

Like I said, the first step is to make the manual changes that you feel are required. In my case, I changed this:

&lt;af:inputText autoSubmit=&quot;true&quot;<br />              id=&quot;NieuweBoekAanvraagUrl&quot;<br />              value=&quot;#{bindings.NieuweBoekAanvraagUrl.inputValue}&quot;<br />              required=&quot;#{bindings.NieuweBoekAanvraagUrl.mandatory}&quot;<br />              rows=&quot;#{bindings.NieuweBoekAanvraagUrl.displayHeight}&quot;<br />              columns=&quot;40&quot; maximumLength=&quot;250&quot;<br />              readOnly=&quot;#{!(createModes.CreateNieuweBoekAanvraag)}&quot; /&gt;<br />

into this:

&lt;af:panelLabelAndMessage label=&quot;Url&quot;&gt;<br />  &lt;af:panelHorizontal&gt;<br />    &lt;af:inputText autoSubmit=&quot;true&quot;<br />                  id=&quot;NieuweBoekAanvraagUrl&quot;<br />                  value=&quot;#{bindings.NieuweBoekAanvraagUrl.inputValue}&quot;<br />                  required=&quot;#{bindings.NieuweBoekAanvraagUrl.mandatory}&quot;<br />                  rows=&quot;#{bindings.NieuweBoekAanvraagUrl.displayHeight}&quot;<br />                  columns=&quot;40&quot; maximumLength=&quot;250&quot;<br />                  readOnly=&quot;#{!(createModes.CreateNieuweBoekAanvraag)}&quot; /&gt;<br />    &lt;af:goLink targetFrame=&quot;_blank&quot;<br />               partialTriggers=&quot;NieuweBoekAanvraagUrl&quot;<br />               destination=&quot;#{bindings.NieuweBoekAanvraagUrl.inputValue}&quot;&gt;<br />      &lt;af:objectImage source=&quot;/jheadstart/images/hyperlink.jpg&quot;/&gt;<br />    &lt;/af:goLink&gt;<br />  &lt;/af:panelHorizontal&gt;<br />&lt;/af:panelLabelAndMessage&gt; <br />

The original item was generated from the formTextInput.vm template, that looks like this:

 

&lt;af:inputText #ITEM_ID_IN_FORM() #ITEM_VALUE_IN_FORM() #ITEM_PROMPT_IN_FORM()<br />     #ITEM_PARTIAL_TRIGGERS() #ITEM_REQUIRED_IN_FORM() #ITEM_ROWS() #ITEM_COLUMNS() <br />     #ITEM_MAXIMUM_LENGTH() #ITEM_READ_ONLY_IN_FORM() #ITEM_RENDERED_IN_FORM()<br />     #ITEM_DISABLED_IN_FORM() #ITEM_HINT()   #DEPENDS_ON_ITEM_PROPS() &gt;<br />  #REGULAR_EXPRESSION_VALIDATOR()<br />  #NUMBER_CONVERTER()<br />&lt;/af:inputText&gt;<br />

How do we change the template to fit our needs? Well, first we copy it: formTextInputURL.vm. All changes are applied to this formTextInputURL.vm template file.

Next we add the autoSubmit="true" attribute and wrap the inputText inside a panelLabelAndMessage and a panelHorizontal:

&lt;af:panelLabelAndMessage&quot;&gt;<br />  &lt;af:panelHorizontal&gt;<br />    &lt;af:inputText autoSubmit=&quot;true&quot; #ITEM_PROMPT_IN_FORM()     <br />      #ITEM_ID_IN_FORM() #ITEM_VALUE_IN_FORM() <br />      #ITEM_PARTIAL_TRIGGERS() #ITEM_REQUIRED_IN_FORM() #ITEM_ROWS() #ITEM_COLUMNS() <br />      #ITEM_MAXIMUM_LENGTH() #ITEM_READ_ONLY_IN_FORM() #ITEM_RENDERED_IN_FORM()<br />      #ITEM_DISABLED_IN_FORM() #ITEM_HINT()   #DEPENDS_ON_ITEM_PROPS() &gt;<br />      #REGULAR_EXPRESSION_VALIDATOR()<br />      #NUMBER_CONVERTER()<br />    &lt;/af:inputText&gt;<br />  &lt;/af:panelHorizontal&gt;<br />&lt;/af:panelLabelAndMessage&gt;<br />&nbsp;

Then we move the #ITEM_PROMPT_IN_FORM() from the inputText to the panelLabelAndMessage – as this is generated into label=" whatever the label should be as derived from Prompt in Form property"  and the label is now set at the panelLabelAndMessage level.

Then we add the goLink item with its wrapped objectImage:

&lt;af:panelLabelAndMessage&quot; #ITEM_PROMPT_IN_FORM()&gt;<br />  &lt;af:panelHorizontal&gt;<br />    &lt;af:inputText autoSubmit=&quot;true&quot; <br />      #ITEM_ID_IN_FORM() #ITEM_VALUE_IN_FORM() <br />      #ITEM_PARTIAL_TRIGGERS() #ITEM_REQUIRED_IN_FORM() #ITEM_ROWS() #ITEM_COLUMNS() <br />      #ITEM_MAXIMUM_LENGTH() #ITEM_READ_ONLY_IN_FORM() #ITEM_RENDERED_IN_FORM()<br />      #ITEM_DISABLED_IN_FORM() #ITEM_HINT()   #DEPENDS_ON_ITEM_PROPS() &gt;<br />      #REGULAR_EXPRESSION_VALIDATOR()<br />      #NUMBER_CONVERTER()<br />    &lt;/af:inputText&gt;<br />    &lt;af:goLink targetFrame=&quot;_blank&quot;<br />               partialTriggers=&quot;${JHS.current.item.bindingName}&quot;<br />               destination=&quot;#{bindings.${JHS.current.item.bindingName}.inputValue}&quot;&gt;<br />      &lt;af:objectImage source=&quot;/jheadstart/images/hyperlink.jpg&quot;/&gt;<br />    &lt;/af:goLink&gt;<br />  &lt;/af:panelHorizontal&gt;<br />&lt;/af:panelLabelAndMessage&gt; <br />

The goLink has its destination set to the contents of the item. To ensure it is refreshed whenever the URL changes, its partialTriggers attribute is set to the item itself – this corresponds with autoSubmit="true" we specified above on the inputText item itself.

Now we can save the new template. The last step is to associate items with this new template:

When we next generate our application, the Url item will be generated with a hyperlink image that allows navigation!

Slightly different approach to Read Only Items

As you may recall I am interested in a slightly different behavior for the items with URLs in them in case they are read-only. Read only URLs should not be displayed as disabled textInput or plain text labels with a hyperlink image attached to them. Instead they should be displayed as hyperlinks – with the URL as source as the value of the Item’s Descriptor as text. Something like this:

Now I need to add a new element to the generator template that gets rendered in case the item is read only (and the Url item has a value!). To make a long story short, the generic custom template now
becomes somethi
ng like:

&lt;af:panelLabelAndMessage&quot; #ITEM_PROMPT_IN_FORM()&gt;<br />  &lt;af:panelHorizontal&gt;<br />    &lt;af:inputText autoSubmit=&quot;true&quot; <br />      #ITEM_ID_IN_FORM() #ITEM_VALUE_IN_FORM() <br />      #ITEM_PARTIAL_TRIGGERS() #ITEM_REQUIRED_IN_FORM() #ITEM_ROWS() #ITEM_COLUMNS() <br />      #ITEM_MAXIMUM_LENGTH() #ITEM_READ_ONLY_IN_FORM() #ITEM_RENDERED_IN_FORM()<br />      #ITEM_DISABLED_IN_FORM() #ITEM_HINT()   #DEPENDS_ON_ITEM_PROPS() &gt;<br />      #REGULAR_EXPRESSION_VALIDATOR()<br />      #NUMBER_CONVERTER()<br />    &lt;/af:inputText&gt;<br />    &lt;af:goLink targetFrame=&quot;_blank&quot;<br />               partialTriggers=&quot;${JHS.current.item.bindingName}&quot;<br />               destination=&quot;#{bindings.${JHS.current.item.bindingName}.inputValue}&quot;&gt;<br />      &lt;af:objectImage source=&quot;/jheadstart/images/hyperlink.jpg&quot;/&gt;<br />    &lt;/af:goLink&gt;<br />  &lt;/af:panelHorizontal&gt;<br />&lt;/af:panelLabelAndMessage&gt;<br />&lt;af:panelLabelAndMessage #ITEM_PROMPT_IN_FORM()<br />   rendered=&quot;#{!(bindings.${JHS.current.item.bindingName}.inputValue == null) <br />              and (!createModes.Create${JHS.current.group.name})}&quot;&gt;<br />  &lt;af:panelHorizontal&gt;<br />    &lt;h:outputLink styleClass=&quot;xa&quot;    <br />                  target=&quot;_blank&quot; #ITEM_VALUE_IN_FORM()&gt;<br />      &lt;h:outputText value=&quot;#{bindings.${JHS.current.group.descriptorItem.bindingName}}&quot;  /&gt; <br />    &lt;/h:outputLink&gt;<br />  &lt;/af:panelHorizontal&gt;<br />&lt;/af:panelLabelAndMessage&gt;<br />&nbsp;

Note that I could have made it more compact by using a single panelLabelAndMessage and set a rendered expression on all of the elements inside, but that turned a little messy I thought.

  1. Sandra,

    You are completely right of course. It should be exactly as you say.

    Do you like the example? Would it make sense to make it part of JHeadstart proper?

    groetjes,

    Lucas

  2. In the last code example, shouldn’t there also be a rendered expression on the first panelLabelAndMessage, with the opposite value as that of the second one? The second panelLabelAndMessage should only show when the item is read-only, and in that case the first panelLabelAndMessage should not be shown. Or is there some other way you achieve that?