Main

Generator Templates Archives

October 13, 2006

Generating Select-Form Layout in Same Page

Ting Rung writes in to ask how he can generate a select-form layout with the select list displayed in the same page as the form items.
Using a custom velocity template, this is easy to generate. Here are the steps:

  • Create a custom template "selectFormGroup.vm" that merges the content of the selectGroup.vm which is used for the select page, and formGroup.vm used for the form page. Click here to download a sample of such a template that uses partial page rendering to refresh the form items when the user selects another entry in the select list.
  • Change the layout style of the group from "select=form" to "form".
  • While selecting the correct group in the navigator, select the templates tab and set the FORM_GROUP template to  your newly created template, for example "default/pageComponent/selectFormGroup.vm".
  • Run the JHeadstart Application Generator.
  • Run your application.
That's all. When you apply these steps to the Jobs group in the HR demo, it will look like this:

Inserting New Row in Table with Overflow Right

When generating a table with overflow right or below, it is not possible to generate the table with one or more empty rows that can be used to insert new rows. The reason for this limitation is that displaying the correct information in the overflow area, requires the notion of a current row in the underlying iterator binding, which is not available for new table rows.

To still allow users to insert a new row in such a table, we can generate a new button that creates a new row in the underlying iterator binding, and make this new row the current row, as shown in the screen shot below:
overflowRightNewRowImage:

To generate this, follow these steps:

  • Create a subclass of JhsCollectionModel, and add the following method to this subclass:
public String createNewRowAtBottomOfCurrentRange()
{
   DCIteratorBinding ib = getRangeBinding().getIteratorBinding();
   int rangeSize = ib.getRangeSize();
   int rowsInRange = ib.getAllRowsInRange().length;
   int insertPos = rowsInRange < rangeSize? rowsInRange: rangeSize - 1;
   Row row = ib.getRowSetIterator().createRow();
   applyModifiedAttrs(row, getDefaultValues());
   ib.getRowSetIterator().insertRowAtRangeIndex(insertPos,row);
   ib.setCurrentRowIndexInRange(insertPos);
   return null;
  }
  • Next, we create a custom template "myCollectionModelbean.vm" based on the standard default/misc/facesConfig/collectionModelBean.vm template. The only change you need to make in this custom template is the class name: set it to the name of your custom class instead of oracle.jheadstart.controller.jsf.bean.JhsCollectionModel.
  • Create a new template "newRowButton.vm" with the following content:
<af:commandButton
action="#{#COLLECTION_MODEL_BEAN().createNewRowAtBottomOfCurrentRange}"
textAndAccessKey="${JHS.nls(${JHS.current.group.displayTitleSingular},
  "NEW_BUTTON_LABEL_${JHS.current.group.name}", "NEW_BUTTON_LABEL" )}"
immediate="true"
onclick="return alertForChanges();"
id="${JHS.current.group.name}NewRowButton">
<f:actionListener
type="oracle.jheadstart.controller.jsf.listener.DoRollbackActionListener"
/>
<af:resetActionListener/>
</af:commandButton>
  • Now, we must configure the generator to use these two custom templates: select the correct group in the navigator and click the Templates tab.
  • In the templates tab, set NEW_BUTTON_NOT_IN_FORM_LAYOUT to the name of your custom button template, for example myapp/button/newRowButton.vm.
  • Set template COLLECTION_MODEL_BEAN to the name of your custom collectionModel template, for example myapp/misc/facesConfig/myCollectionModelBean.vm.
  • Run the JHeadstart Application Generator
  • Run your application.
Note that the New button now appears as a page level button. When you have detail groups displayed on the same page, the new button will appear as a group-level button, just below the table.
We could also have chosen to add the button to the table selection facet, just like the "Details" button generated for a "table-form" layout. However, the selection facet is only rendered when the table contains at least one existing row, which would make it impossible to create a new row in an empty table.

Finally, this example illustrates that custom templates are not just for layout customizations. They can also be used to specify the usage of custom subclasses of the JHeadstart Runtime classes, allowing you to change or extend the default JHeadstart runtime behaviors.
 

October 20, 2006

Showing Parent Lookup Details with Edit Link

David posts on the JHeadstart Discussion Forum: on a page for editing an person, he wants to have a very condensed report of who the boss (manager) is together with a link,
on the same page as the base person (employee), so that he can use the link if
needed to edit the "boss". Other requirements are: 1) to display some differentiated columns (for example name, lastname, town,
country, ...) with their header for the boss and 2) more generally, having a similar look-and-feel of the page as other pages, and keeping
things clearly separated.

Here is my suggested solution, based on the HR schema that is also used in the JHeadstart Tutorial:
Manager Details with Edit Link Image: The lookup attributes of the manager are shown in a separate Item Region, together with a hyperlink that deeplinks to the page to edit the manager.<br>

The example has a link to the same group, but the solution described here works just as well if you link to another group. If you apply it, you will be using partial page rendering, deeplinking custom templates en custom properties, while only making some easy changes in JDeveloper.

How to show parent lookup details with an edit link

First change the relevant View Object in the Model project:

  1. Edit the ADF BC View Object for Employees and add the Entity for the Manager (check that the correct Entity Association is used in the bottom right corner of the panel).
  2. Add the desired lookup attributes you want to show of the Manager, and optionally rename them to make them easily recognizable.
  3. Ensure that the lookup attribute for the id of the Manager is not marked as Primary Key.
  4. Ensure that the SQL Query where clause performs an outer join if the manager relation is optional.
  5. Test the View Object with the ADF BC Tester
Now add a Generator Template and change the Application Definition in the ViewController project:
  1. Save the custom Velocity template {manilaSuite.gems.includeGem (26)} in a templates/custom folder of your ViewController project.
  2. Open the Application Definition, go to the Employees Group, and click the button to synchronize the items. This will add the new Manager Lookup attributes as items.
  3. Create a new Item Region for the Employees Group, and drag and drop the Manager Lookup items and the Employee item for changing the Manager to the new Item Region.
  4. Put in an appropriate Title for the region, set Columns to 1 and Width to 10%.
  5. Set the Depends On Item property (only visible in Expert Mode) for the Manager Lookup items to the Employee item that changes when you update the Manager (the ManagerId item in this case). This ensures that when you change the Manager, the lookup attributes are refreshed.
We will turn the Manager Lookup item that contains the id of the manager (not the ManagerId, but the EmployeeId of the manager entity) into an edit deep link. I will call this item the ManagerEmployeeId.
  1. In the Application Definition Editor, go to the ManagerEmployeeId item, and go to the Templates tab. Set the FORM_TEXT_INPUT template to the new template formDeepLink.vm you downloaded.
  2. Go back to the Properties tab, and set Custom Property 1 (only visible in Expert Mode) to the name of the group you want to link to (in this case Employees). You can put an explanation in Custom Property Description 1.
  3. Go to the Employees group, and set Type of Deep Linking (only visible in Expert Mode) to Query By Key Value.
  4. Set the Deep Linking Key Expression to the JSF EL expression #{param.EmployeesId}.
If you want to add a similar deeplink in a table layout, download {manilaSuite.gems.includeGem (27)} and use it as the TABLE_TEXT_INPUT template.

For more information about dependent fields, deep linking and custom templates, see sections 8, 9 and 10 of the JHeadstart Tutorial. See also the JHeadstart Developer's Guide chapter 3, section Customizing Page Layout Generation.

Note: in this case the deep link goes to the same group, but the technique also applies when linking to any other group.
In case you want to link to the same group, there is an alternative solution possible: instead of a deeplink, put an actionListener on the commandLink, to set the current row using setCurrentRowWithKey, setCurrentRowWithKeyValue or queryByKeyValue. Let the actionListener reference a suitable action binding, that you manually add to the page definition. If you uncheck the group property Clear Page Definition Before Generation?, your change will be preserved.

November 9, 2006

Deep Link to Insert a New Row (switching to the Create Mode of a Form Layout)

On the JHeadstart Discussion Forum, David Pistolero explains how to create a deep link for creation of a new row in a form-style JHeadstart Group.

See how you can use JHeadstart's Velocity Generator Templates to generate JSF / ADF Faces pages with a hyperlink that goes to another page of your application. When the hyperlink is clicked, the target page (which has a form layout style) invokes an ADF CreateInsert operation, and switches the page into JHeadstart create mode.

The JHeadstart create mode allows the same page to be used for both inserts and updates. See the JHeadstart Developer's Guide, section "Create/Update Page Mode".


Thank you for your contribution, David!

November 30, 2006

Generating Custom Resource Bundle Entries

In JHeadstart jspx pages, you can reference entries in the JHeadstart resource bundle (usually called ApplicationResources.properties), using the EL expression #{nls['KEY']}, where KEY is the key of the desired resource bundle entry.

Manually adding your own message

If you want to add your own message, you can of course write an entry in the resource bundle:

CONFIRM_DELETE=Are you sure you want to delete this row?

Then you can use this message in your JSF page by specifying:

#{nls['CONFIRM_DELETE']}

Generating the message into the page

The next level is to include this EL expression in a custom Generator Template. For example when adding a warning message to a delete button, which is also described in Lucas Jellema's post Generate 'Delete with Confirmation' in JHeadstart applications.

In the Velocity Generator Template for your custom Delete Button you could use something like:

onclick="return confirm('#{nls['CONFIRM_DELETE']}');"

That way you can generate the page, but you would still have to add the message manually to the ApplicationResources.properties file.

Generating the message into the Resource Bundle

One step further is to use the JHeadstart routine JHS.nls in your Velocity template. This method in the JhsVelocityContext class (see the JDeveloper Help menu, JHeadstart Documentation Index, Javadoc of the JHeadstart Application Generator) has many overloaded variations. The simplest takes two String arguments:

nls(java.lang.String s, java.lang.String key)

It creates a resource bundle entry KEY=s, and returns #{nls['KEY']}. In the delete warning example you would put in the generator template:

onclick="return confirm('${JHS.nls("Are you sure you want to delete this row?", "CONFIRM_DELETE")}');"

And it would create a resource bundle entry

CONFIRM_DELETE=Are you sure you want to delete this row?

You can make it more specific for each group while keeping it generic, by changing it to (suggested by Aino Andriessen):

onclick="return confirm('${JHS.nls("Are you sure you want to delete this ${JHS.current.group.displayTitleSingular}?", "${JHS.current.group.name}_CONFIRM_DELETE")}');"

This will result in (example for the Customers group):

onclick="return confirm('#{nls['CUSTOMERS_CONFIRM_DELETE']}');"
                   
and a resource bundle entry

CUSTOMERS_CONFIRM_DELETE=Are you sure you want to delete this Customer?

When the user clicks the Delete button, (s)he will see this:

Delete Warning: Javascript popup dialog to let the user confirm the delete<br>

December 22, 2006

Generating a Custom Look and Feel using JHeadstart

A popular question on the JHeadstart Discussion Forum is how to create a more "webby" custom look and feel, instead of the default Oracle Browser Look and Feel (BLAF) that is generated by JHeadstart .

The first step in customizing the look and feel is using the skinning feature of ADF Faces. There is a How To on OTN that explains the steps involved in creating a custom skin for your ADF Faces application. With a custom skin, you can customize layout characteristics which are typically defined through cascading style sheets: fonts, colors, icons, images, margins and so on. To figure out how you can change the appearance of the various ADF Faces user interface components, this Skin Selectors document is really useful.

While ADF Faces skinning is a nice feature, it does not allow you to perform more "radical" layout customizations which include rearranging the overall page layout. For example, in many web sites, the menu is shown in a nested structure at the left side of the page.

Customizations like this can easily be achieved by creating a set of custom Velocity templates and configure the JHeadstart Application Generator to use this custom set of templates. Before we go into the technical details, let's first tease you with two screen shots of the same JHeadstart-generated application. The screen shot below shows a page generated with the default templates, resulting in the well-known Oracle Browser Look and feel:
defaultlaf_small_image:

Now, by applying a set of custom templates, in combination with a custom ADF Faces skin, we can regenerate the application with the OTN look and feel:
customlaf_small_image:

As you can see the page is divided in multiple regions: header, footer, left side, right side, and the page content in the middle. The menu 1 and menu2 tabs have been combined into one nested menu structure. Furthermore, the menu item labels and button labels will turn red when the mouse moves over it. 
 
If you want to apply a custom look and feel to your own application, you can benefit from the work done to create the OTN "look and feel":

  • Download the CustomLafTemplates10132.zip zipfile (or CustomLafTemplates10131.zip when still using JHeadstart 10.1.3.1) and unzip it in the templates directory of your ViewController project.
  • Download the CustomLafWebResources10132.zip zipfile (or CustomLafWebResources10131.zip
    when still using JHeadstart 10.1.3.1) and unzip it in the html root directory (typically named "public_html) of your ViewController project.
  • Open the adf-faces-config.xml file in the WEB-INF file and set the skin family to "customlaf".
  • Open the JHeadstart Application Definition Editor, select the top-level Service node, select the templates tab, and set the property "template Binding File (.jtp) to "customlafTemplateBindings.jtp" as shown in the picture below.
jde_editor_templates_image:
  • Run the JHeadstart Application Generator
  • Run your application!
That's all. Now you are all set to create your own custom look and feel by modifying this sample OTN look and feel. To make it easier to tailor the sample files for your specific needs, here are some pointers on how this custom look and feel is implemented:
  • A custom ADF Faces skin named "customlaf" is defined in the adf-faces-skins.xml file in WEB-INF directory. When you open this file, you will see that the style sheet name is set to "customlaf/css/customlaf-faces.css" In this CSS file you can change the appearance of ADF Faces components by specifying  the appropriate selectors that you can find in the aforementioned link.
  • All custom velocity templates that should be used by the JHeadstart Application Generator are listed in the file customlafTemplateBindings.jtp, located in the templates/config directory of your ViewController project. If you need to create additional custom templates, you can add them to this file. You can find the corresponding template name key as comment in the generated pages.
  • The overall page structure is defined in customlaf/page/dataPage.vm.The most significant difference with the default dataPage.vm template is the absence of the &lt;af:panelPage> element and its various facets like "branding", "menuGlobal" and "messages". Instead of this element, the template contains a html-like set up of the page that defines the various regions on the page:
Header
Left Side

Page Body

Page Title
Breadcrumbs
Messages
Parent Context Info
Page Content (groups)
Right Side
 Footer

  • The actual page content is driven by the xxxPageContent.vm templates, also located in the customlafpage directory.
  • The content in the header, footer, leftSide, and rightSide areas is defined in ADF Faces regions by the same name, to prevent the actual content of these areas from being duplicated in each and every page.
  • The leftSide region is populated with content based on the menu1.vm template. This template has been customized to loop over the top level groups to create level 1 menu entries, and, for each top-level group it also loops over the child groups to create the nested menu 2 entries.
  • For each button template a custom version is created that specifies the button style class, and the onmouseover and onmouseover properties to get the "rollover" effect with the red-colored button label.
  • The button style class, and other style classes used in the templates are defined in /customlaf/css/customlaf.css. This means we use two css files, the other file, /customlaf/css/customlaf-faces.css holds the skinning settings. This could be merged into one style sheet if you like. You can do this by changing the style sheet name in adf-faces-skins.xml.
Once again, this example illustrates the huge power of the JHeadstart Velocity generator templates. 100% generation is doable, regardless of your layout requirements.
I hope it will get you started quickly with generating any layout you want!

April 7, 2007

How to handle impatient end users

By using JHeadstart of course! They will get a sophisticated ADF-JSF application much faster than without JHeadstart. But that was not really the point of writing this blog entry.
A few days ago I accidentally stumbled into a very nice property of ADF Faces command buttons and command links: the boolean blocking property. Here is the online help of this property:

If set to TRUE the component will start blocking user input when the action is initiated. The blocking will stop when a response is received from the server.


So, if you have impatient end users who resubmit a page before the previous request was completed, and they complain about weird error messages, then this property is your friend! I did a quick test with a button that fires the Java sleep command for 10 seconds, and it works like a charm, the browser page is "frozen" for 10 seconds.

The save button is a typical candidate for this property, and to generate your JHeadstart application with this property you can use a custom Velocity template for your save button:


  • Make a copy of saveButton.vm, name it something like blockingSaveButton.vm.

  • Add the blocking="true" property to this custom template.
  • Open the Application Definition Editor, select the top-level Service node, go to the Templates tab, and set the SAVE_BUTTON template to the name of your custom "blockingSave" template.
  • Generate your application
That's all, in 1 minute you added this property to the save button  in all your pages. Long live 100% generation!

April 9, 2007

Generating a Cancel Button

Over in the JHeadstart Discussion Forum, Raghu asks how he can add a cancel button to the transactional pages generated with JHeadstart. Since this a recurring question, I will answer it here.

The Cancel button should appear in all pages where you can insert, update or delete data. In short, all pages where a Save button is present to commit the changes. So, the easiest way to add a Cancel button to your transactional pages, is by modifying the Save button template, and add a Cancel button inside this template that appears side-by-side with the Save button. Here are the steps:


  • Make a copy of saveButton.vm, name it something like SaveAndCancelButton.vm.

  • Add the Cancel button as follows to this template:
#if (!$JHS.page.pageReadOnly)

  &lt;af:commandButton text="#CANCEL_LABEL()" immediate="true"
      actionListener="#{bindings.Rollback.execute}"
      #JHS_PROP("rendered" $JHS.page.saveButtonRenderedExpression)
      action="Start${JHS.current.group.baseGroup.name}"   
      onclick="alertForChanges();"
      id="${JHS.current.group.name}CancelButton">
    &lt;f:actionListener type="oracle.jheadstart.controller.jsf.listener.ResetBreadcrumbStackActionListener"/>
    &lt;af:resetActionListener/>
  &lt;/af:commandButton>
               

  &lt;af:commandButton actionListener="#{bindings.Commit.execute}"
      action="Commit" #VALIDATE_FORM()
      #JHS_PROP("rendered" $JHS.page.saveButtonRenderedExpression)        
      textAndAccessKey="${JHS.nls(${JHS.current.group.displayTitleSingular},
       "SAVE_BUTTON_LABEL_${JHS.current.group.name}", "SAVE_BUTTON_LABEL" )}"
                  id="${JHS.current.group.name}SaveButton">
   &lt;af:resetActionListener/>
  &lt;/af:commandButton>         
#end



  • Open the Application Definition Editor, select the top-level Service node, go to the Templates tab, and set the SAVE_BUTTON template to the name of your custom "SaveAndCancelButton" template.
  • Generate your application
That's all, in 1 minute you added a cancel button to all your transactional pages. Long live 100% generation!

Note that in the example the action property is set to go to the first page within the group. You can easily change this if you like. For, example, you can use the first custom property of a group which can be set in the Application Definition Editor, to specify the navigation action for the Cancel button by setting the action property to "${JHS.current.group.property1}"

July 31, 2008

Changing the default query operator in JHeadstart Search Areas

In JHeadstart Quick Search and Advanced Search, for each search item you can define a Query Operator. This operator determines how to query the data. Examples are contains, endsWith and greaterThan. See the JHeadstart Developer's Guide, section 7.2.4 for instructions how to change the Query Operator for an item. You can even let the application user choose the query operator.

By default, the ‘StartsWith’ operator is used for String items. In all other cases the equality operator is used.

But what if you want all your String items to use a different query operator? You don't want to explicitly set the query operator for every item.

The solution is: modify the JHeadstart Generator Template that creates the Search Beans, and add a managed property to the managed bean to set the defaultStringOperator to another value.

The next question becomes: what value to use? The 'StartsWith' operator applies the 'like' operator, and adds a wildcard % at the end of the search term. What if you want to keep on using the 'like' operator, but without the added wildcard?

You could check the allowable values of the Query Operator property in the JHeadstart Application Definition (at Item level). Unfortunately it does not list a "like" operator. You could choose the "is" operator, but then any wildcards typed in by the end user would be taken literally. You want the use of wildcards, but only if typed in!

Section 7.2.6.2 of the JHeadstart Developer's Guide explains that JHeadstart's QueryCondition class is responsible for translating the query operator names to the appropriate SQL operators and wildcard usage. Taking a look at the source code of oracle.jheadstart.model.QueryCondition (in JDeveloper, select a JHeadstart project, click Control+Minus and type in QueryCondition), sheds some light on the issue. If the query operator is "startsWith", the SQL operator is set to "like" and the wildcardUsage is set to "suffix". If the operator does not match any of the predefined values, no transformation is applied, and the passed in value is set directly as SQL operator. So, to achieve that the SQL operator is set to "like" and no wildcard is added automatically, we must set the query operator to "like".

To summarize, here are the steps to apply:

  1. Copy the JHeadstart template default/misc/facesConfig/searchBean.vm to your location for custom templates, for example custom/searchBeanDefaultStringOperator.vm. For more information about using custom templates, see the JHeadstart Developer's Guide, section 4.7.2.
  2. Add the following lines just before the last line that contains the end of the bean( </managed-bean> ):
    <managed-property>
    <property-name>defaultStringOperator</property-name>
    <value>like</value>
    </managed-property>
  3. Modify your config/customTemplateBindings.jtp file (you may have used a different name) and add a line:
    SEARCH_BEAN=custom/searchBeanDefaultStringOperator.vm
    If you don't have such a file yet, you can create one in the config folder. It can be empty besides the above line.
  4. If you didn't have a customTemplateBindings.jtp yet, you will also have to specify in your Application Definition file(s) that you want to use this configuration file. You do that at Service level, in the Templates tab, the first property. Set Template Binding File (.jtp) to customTemplateBindings.jtp.
  5. Run the JHeadstart Application Generator for the Application Definition(s).

October 8, 2008

Clear search criteria on lov start-up in JHeadstart 10.1.3

A list of values (LOV) is an ADF Faces component that allows the user to select an item from a popup window with a list of items and load the value(s) into the specified field(s). Oracle JHeadstart automatically generates several search features for LOV type fields. It generates the simple and advanced search functionalities, in addition of validating text entered against the list, showing the records that meet the filter or, if there is just one match, loading the values in the fields. The criteria and results of the latest executed search are maintained during the session. This behavior is the same for any search executed on any ViewObject usage.
It can be required for LOV type fields not to save criteria and results from the previous search but instead show the complete list to choose in the lookup. To achieve this behavior it is necessary to clear the search criteria and re-execute the query with no filter values. This represents a performance penalty by having to execute an extra query each time a LOV is opened. The positive side is that it is only necessary to execute this extra query when the previous one was executed with not null criteria values.
The steps to implement this solution in JHeadstart 10.1.3 are described below:

  1. Extend the oracle.jheadstart.controller.jsf.bean.LovItemBean class.
  2. Overwrite the setLovSearchBean method, which is invoked several times during the use of a LOV:
    • Loading a page that contains any LOV type field.
    • Opening the window associated to a list of values.
    • Validating a string against a LOV.
    • Selecting a value from a LOV
    • Closing the window associated to a list of values.

    This method receives an object of type oracle.jheadstart.controller.jsf.bean.JhsSearchBean that contains the objects where the search criteria are kept:
    • SearchText and Criteria when Quick Search is executed.
    • Criteria when Advanced Search is executed.

    To ensure that a full query is executed if the previous search was more restricted, change the overridden method as shown below:
           public void setLovSearchBean (JhsSearchBean lovSearchBean){
             JhsSearchBean lsb = lovSearchBean;
             if(lsb!=null && (lsb.getSearchText()!=null || lsb.getCriteria().size()>0)) {
                lsb.setSearchText(null);
                lsb.getCriteria().clear();
                lsb.quickSearch(); 
             }
             super.setLovSearchBean(lovSearchBean);
           }
    Only when SearchText object is not null or Criteria object is not empty, the search criteria is cleared (lsb.setSearchText(null) lsb.getCriteria().clear()) and the search with no filter values is re-executed (lsb.quickSearch()).
  3. Create a new version of the velocity template misc/facesconfig/lovItemBean.vm which will reference the new class created in the first step:
           <managed-bean>
              <managed-bean-name>${bean.beanName}</managed-bean-name>
              <managed-bean-class>new LovItemBean class created</managed-bean-class>
              <managed-bean-scope>request</managed-bean-scope>
              …
           </managed-bean>
    See section 4.7 of the JHeadstart Developer's Guide for more information about customizing generator templates.
  4. Associate this new template to the LOVs requested to have this behavior.

About Generator Templates

This page contains an archive of all entries posted to JHeadstart Blog in the Generator Templates category. They are listed from oldest to newest.

Forms to ADF is the previous category.

JDeveloper IDE is the next category.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type and Oracle