Keeping up appearances with ADF 11g RichFaces – Context Sensitive Styling in a world of imperfect HTML with dynamic PageTemplate and Page Fragment includes

 

You may not necessarily know me for all the useful things I do. I tend to find nooks an crannies in JDeveloper 11g and ADF 11g that are no real use to people doing a real job. However, today I have got something to share that is actually useful. I know this as I ran into a demand for it at a customer I visited today.

In short, the situation was like this: we are creating a web application that needs to have several appearances – not very much alike. The basic functionality – data entry, data display, navigation options – is by and large the same. However, there are substantial differences in the look of these various appearances. And no – it is not just styling or skinning, though that is certainly part of it. What in one appearance maybe located on the top of the page may go right into the center of the page in another appearance. And what in one incarnation maybe a search area with three items, positioned in a horizontal group, all of them plain inputText items may in another incarnation be implemented with two input elements, one a group of radio buttons and a dropdown, positioned in a vertical layout.

The UI designers I was conferring with were at first not happy, when they inspected the HTML rendered by ADF 11g RichFaces. Far too many tables used to their liking. Using HTML table elements for creating the layout of the page is fairly rigid, somewhat old fashioned approach, they informed me. And I am aware of that fact. They prefer almost unstructured HTML that they can apply their CSS wizardry to. And of course they are quite right. However, JSF (or JSP or .NET libraries) are great for productive, declarative development with intricate dependencies on backend services – and unfortunately the world of Web Applications is not a perfect one.

To my relief – I have had some difficult conversations in the past – these UI designers were quite willing to be pragmatic about it and work with the output they were getting. In fact, they were even prepared to step out of their world of CSS & JavaScript only and come into JDeveloper. To work with the ADF skinning. And to discuss how we could make optimal use of ADF RichFaces to get ourselves the different appearances required in this application. With maximum reuse – it was not our intention to create every page once for every appearance we had to support. The basic set of input elements, data (control) bindings and navigation controls was the same across all appearances.
 

Dynamic Page Templates

We first turned to page templates, as they are responsible for much of the overall page layout (structure). Typically a template is used to defined a structure that can be applied to a large number of pages in an application. And that can be modified to achieve an application wide change in look & feel. However, we can use page templates for slightly different goal as well. Since the page template reference in a page is dynamic – can be specified using an EL expression – it can be set dynamically, context sensitive when running the application. So if the desired appearance can be read from some context variable, the page can switch to the desired template on the fly.

The requirements for this to make sense are of course that each template used has the same facets defined and uses the same parameters/attributes. Furthermore, if the pageTemplates have their own PageDefinitions, all of the should be refreshed in the executables section of the page definitions for the pages that use the templates.

In this example, I have created to page templates, both with a single facet (facet1). The templates are nothing as wildly spectacular of courseas the ones we create in the project I mentioned above. But they serve to prove the point.

I have created a single JSF page – untitled1.jspx – that has a reference to the template it is based on. Note that the viewId is not a static reference but an EL expression:

<af:pageTemplate  id="t1" viewId="#{bean.template1?'/templateDef1.jspx':'/templateDef2.jspx'}">

The bean referred to has three boolean properties, one of which is called template1. When set to true, templateDef1.jspx should be applied to the page and when set to false the other template – templateDef2.jspx – should be invoked to provide the page appearance.

Though I tried I have not been able to have the template change take effect in a PPR request – perhaps that is slightly pushing it. But changing the checkbox bound to the boolean property and submitting the form has the effect of switching the style of appearance:
 

<af:group>
  <af:selectBooleanCheckbox id="templateSelector"
                            text="Yes or No?"
                            value="#{bean.template1}"
                            label="Template 1?"
                            autoSubmit="true"/>
  <af:spacer width="15"/>
  <af:commandButton text="Confirm Template Choice"/>
</af:group>

The next two screenshots show the same page, with two different templates applied. I’ll grant you, they look horrible. All I try to do here is demonstrate how two appearances of the same page can be achieved by dynamically switching the template.

Keeping up appearances with ADF 11g RichFaces - Context Sensitive Styling in a world of imperfect HTML with dynamic PageTemplate and Page Fragment includes dyntempladf0001

Uncheck the first chedckbox and press the button to get this – same page, different template:

Keeping up appearances with ADF 11g RichFaces - Context Sensitive Styling in a world of imperfect HTML with dynamic PageTemplate and Page Fragment includes dyntempladf0000

Note: the templates are both defined with two facets into which the pages can ‘plug their content’:

  <af:pageTemplateDef var="attrs">
    <af:panelHeader text="Template number one" messageType="info"
                    inlineStyle="background-color:Olive;">
      <f:facet name="legend">
        <af:facetRef facetName="facet2"/>
      </f:facet>
      <f:facet name="info">
        <af:image shortDesc="AMIS logo"
                  source="http://www.amis.nl/gfx/img_amis_logo.gif"/>
      </f:facet>
      <af:spacer height="50"/>
      <af:panelBox text="Fancy page specific stuff"
                   inlineStyle="background-color:Silver;" background="medium">
        <f:facet name="toolbar"/>
        <af:facetRef facetName="facet1"/>
      </af:panelBox>
    </af:panelHeader>
    <af:xmlContent>
      <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
        <display-name>templateDef2</display-name>
        <facet>
          <facet-name>facet1</facet-name>
        </facet>
        <facet>
          <facet-name>facet2</facet-name>
        </facet>
      </component>
    </af:xmlContent>
  </af:pageTemplateDef>

Dynamic Page Fragments

Page Fragments also turn out to be able to play another role that what seems to be their primary purpose. First and foremost, Page Fragments allow us to break large, complex pages into smaller, more manageable (also Subversionable) pieces. A close second benefit of using page fragments is the ability to reuse those fragments in more than one page. Today, with the request for multiple appearances of what basically is the same page, a third role emerged for the page fragment: they provide a means to conditionally – context and appearance sensitively – include pieces of content in a page or not.

Page Fragments are for all intents and purposes normal JSF pages, except for the fact that their file extension is .jsff and their parent elements are not f:view and af:document. A page fragment is included with a jsp:include tag:

<jsp:include page="/untitled1.jsff"/>

However, such an include can easily be wrapped in a container, such as panelGroupLayout, whose render attribute is dynamically set using an EL expression:
 

<af:panelGroupLayout rendered="#{bean.showF1}">
  <jsp:include page="/untitled1.jsff"/>
</af:panelGroupLayout>

In this snippet, the live inclusion of fragment /untitled1.jsff depends on the showF1 boolean property on the bean. In the page shown in the screenshot below, the two checkboxes govern the boolean properties showF1 and showF2 that specify whether or not the two fragments are included:

<af:panelGroupLayout id="pgl" partialTriggers="sb1 sb2">
  <af:panelGroupLayout rendered="#{bean.showF1}">
    <jsp:include flush="true" page="/untitled1.jsff"/>
  </af:panelGroupLayout>
  <af:panelGroupLayout rendered="#{bean.showF2}">
    <jsp:include flush="true" page="/untitled2.jsff"/>
  </af:panelGroupLayout>
</af:panelGroupLayout>

The checkboxes themselves are bound to the bean properties, fire autoSubmit and are responsed to by the panelGroupLayout that wraps the two page fragment includes:
 

<af:selectBooleanCheckbox id="sb1"
                          value="#{bean.showF1}"
                          label="Show Fragment 1?" autoSubmit="true"/>
<af:selectBooleanCheckbox id="sb2"
                          value="#{bean.showF2}"
                          label="Show Fragment 2?"
                          autoSubmit="true"/>

Whatever is inside the page fragments does not really matter all that much. Note however that the page fragments are included (merged or mashed) into the page and rely on the ADF PageDefinition (binding container) for the page that absorbs them. They can be consumed by many pages.

The two templates and two fragments that can both be included or not lead to eight different appearances – all of the equally ugly. Let’s look at three of them. And remember: you are looking the same page in all three cases. They have two different templates applied and pick one of two fragments:

Keeping up appearances with ADF 11g RichFaces - Context Sensitive Styling in a world of imperfect HTML with dynamic PageTemplate and Page Fragment includes dyntempladf0002

Keeping up appearances with ADF 11g RichFaces - Context Sensitive Styling in a world of imperfect HTML with dynamic PageTemplate and Page Fragment includes dyntempladf0003

Keeping up appearances with ADF 11g RichFaces - Context Sensitive Styling in a world of imperfect HTML with dynamic PageTemplate and Page Fragment includes dyntempladf0004

 

Resources

Download JDeveloper 11g Application for this article: ADFPageTemplate.zip (18 kb).

2 Comments

  1. Lucas Jellema October 23, 2008
  2. Eric van Mourik October 22, 2008