The ADF 11g Area Template – for micro level layout design patterns

 

ADF 11g offers various facilities for reusables. To name a few:

Task Flows provide packaged, self contained functionality that consists of both User Interface and Data Bindings and potentially even some process logic and multi step navigation. Task flows can expose parameters that accept values used to dynamically influence the task flow’s behavior. Task flows do not expose facets (which could be an interesting extension of the task flow mechanism). Task flows can publish events that ADF can propagate to consumers outside the region that consumes the task flow.

Declarative components provide a way of packaging reusable clusters of ADF Faces components – usually a fairly small number – that may define parameters and facets through which a usage of the component can be configured and injected with additional content.

Page Templates are a third reusable – typically used to provide a page with one or more containers to hold the page’s content in combination with a frame that has some boilerplate elements – for example titles, menu-items etc. Page templates expose one or more facets into which the contents from the consuming page is injected. Page templates can also publish attributes through which the consumer can pass information used to influence the templates look & feel. Page templates can use data bound components and will then have their own Page Definition.

This article will focus on the Page Template and will explain why this component is somewhat oddly named.

When a page is created, we can select a page template (a JSPX file that exposes one or more facets and possibly attributes). An <af:pageTemplate> component is added to the new page. We can specify the values for any of the attributes defined for the template, for example:

   <af:pageTemplate viewId="/SHOPtemplate.jspx">
      <f:attribute name="pageTitle" value="Post an Advertisement"/>
      ....

This component typically has one or more facets into which the page contents is injected:

      <f:facet name="pageBody">
        <af:panelHeader id="productPH" text="Product Details" size="-1">
          <af:inputText id="nameIT" label="Name" required="true"
                        value="#{advertisement.name}">
          ....

When the page is run, the components from the page template are read and merged into the page that is based on or as is a better way of describing it, consumes the template. From the centrally defined template, components are merged into the page and based on the attributes some dynamic boilerplate can be set. The page is rendered after this run time merge has taken place – and the end result looks no different than when the contents from the template would have been part of the page proper to begin with. The main page template usually defines the header, footer and side bar of the application’s pages.

The real benefits of the template become apparent when we are dealing with larger numbers of pages – all with the same structure and boilerplate elements. As the template gets reused in every page, we get to reuse the template’s contents over and over again. Then we arrive at true bliss when for some reason the global page structure or the common layout elements and boilerplate items need to be changed. By modifying the template, we effectively modify the run time appearance of every page based on it.

Note: the page template can have an associated page definition with data bindings. If that is the case, the template’s binding container is initialized and refrehsed along with the binding container for the page itself. The page’s page definition will have a <page path="reference to template’s page definition" > element in its executables section. This makes all the bindings in the template available in every page that uses the template. This in turn makes it easy to create a generic or at least reusable set of data bindings and attach it to many pages.

So far nothing new, as this is well known behavior for the page template. Howver, I recently came across a useful characteristic of the page template mechanism: even though the component is called page template and only seems to be configurable at page level and when the page is first created, in actual fact a page can contain multiple <af:pageTemplate> components. This means that page can leverage multiple templates to provide not just the overall page layou structure and boilerplate components, but also apply templates for smaller scale areas. For example the mainPageTemplate can provider the page header and footer. Depending on the UI patterns present in the page – such as Tree-with-Detail-Form, Table-ande- Chart, Master-Form-Detail-Table etc. – area template can be used to provide a centrally managed, consistent look & feel for all occurrences of such UI pattern. Page template can be used at fairly small scale – alost the same level as declarative components. Note that templates usually provide some boilerplate along with some containers to organize the content that page injects while declarative components provide the cluster of components themselves.

As an example, let’s look at the following page. This page displays a table of products on offer. When the user clicks on a row in the table, the details for the product are shown in the detail form. The table with detail form is an example of a UI pattern our UI designers have identified and they have prescribed an approach for occurrences of that pattern. Furthermore, they have created a page structure for all our pages that consists of a header, footer and side bar. The exact contents of those areas is to be determined later, however they have created a page template. At this point they have specified that all pages should pass their title to the template as well as a page identifier to be used for the global menu.

The main template page is mainPageTemplate.jspx. It exposes one facet (body) and two attributes (pageTitle and menu identifier). Page EmployeesPage is based on this template and passes its page title and menu identifier:

        <af:pageTemplate viewId="/mainPageTemplate.jspx" id="mainPageTID">
          <f:facet name="body">
...
          </f:facet>
          <f:attribute name="title" value="People Page"/>
          <f:attribute name="pageIdentifier" value="peoplePage"/>
        </af:pageTemplate>

Inside this body facet, the page uses a second page template, called TableWithDetailFormTemplate.jspx. This template exposes two facets, one for the table and one for the form:

  <af:pageTemplateDef var="attrs">
    <af:panelStretchLayout id="id1" inlineStyle="width:50%;">
      <f:facet name="center">
        <af:panelSplitter id="id2" splitterPosition="258"
                          orientation="vertical">
          <f:facet name="first">
            <af:panelHeader id="id3"  text="All #{attrs.recordLabel}s">
              <af:panelCollection id="id4" >
                <af:facetRef facetName="table"/>
              </af:panelCollection>
            </af:panelHeader>
          </f:facet>
          <f:facet name="second">
            <af:panelGroupLayout id="id5"  layout="scroll"
                                 xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
                                  inlineStyle="background-color:Yellow;">

              <af:panelHeader id="id6"  text="Current #{attrs.recordLabel}"
                              inlineStyle="background-color:Yellow;">
                <f:facet name="context">
                  <af:facetRef facetName="detailForm"/>
                </f:facet>

This template can be used to provide the structure and base boilerplate content for a specific area in a page – an area that should contain an instance of the table-with-detail-form pattern. Using the template is done with the following snippet of code:

<af:pageTemplate viewId="/TableWithDetailFormTemplate.jspx" id="tableDetailPageTID">
                <f:attribute name="recordLabel" value="Person"/>
                <f:facet name="table">
                  <af:table value="#{bindings.People.collectionModel}" var="row"
...
                </f:facet>
                <f:facet name="detailForm">
                  <af:panelFormLayout maxColumns="2">
...
                </f:facet>
              </af:pageTemplate>

Note that this snippet provides the name of the template, values for the template’s attributes and content for the template’s facets. Note for example how the table facet is injected with a table component that gets wrapped in a PanelCollection inside the template.

I have created two pages that both make use of the main page template as well as the TableWithDetailFormTemplate. One is on people:

The ADF 11g Area Template - for micro level layout design patterns areateamplate1

And the other one – an entirely different page – is on products:

The ADF 11g Area Template - for micro level layout design patterns productpage 9

The pages themselves are somewhat different as they refer to different underlying data bindings. Thanks to the template, they come out with a consistent look and feel, horrible as that look and feel may be.

The references to the templates in both pages are similar – the new thing to me is that one page can have more than one – and in fact virtually unlimited- template usage (multiple <af:pageTemplate> components).

  <f:view>
    <af:document>
      <af:messages/>
      <af:form>
        <af:pageTemplate viewId="/mainPageTemplate.jspx" id="mainPageTID">

          <f:facet name="body"> 
<af:pageTemplate viewId="/TableWithDetailFormTemplate.jspx" id="tableDetailPageTID"> <f:attribute name="recordLabel" value="Person"/> <f:facet name="table"> <af:table id="table" value="#{bindings.People.collectionModel}" var="row" ... </af:table> </f:facet>
<f:facet name="detailForm">
<af:panelFormLayout id="detailForm" partialTriggers="id4:table" maxColumns="2" labelWidth="20%"> ... </af:panelFormLayout> </f:facet>
</af:pageTemplate>
</f:facet>
<f:attribute name="title" value="People Page"/>
<f:attribute name="pageIdentifier" value="peoplePage"/>
</af:pageTemplate>
</af:form> </af:document> </f:view>

Note: the viewId in the <af:pageTemplate> component can be set as an EL Expression. This means that you can determine at runtime, based on some dynamically evaluated logic, which template to apply to a certain area in your pages -provides these templates all support the same facets and attributes. A more thorough description of this dynamic template assignment can be found here: https://technology.amis.nl/blog/3702/keeping-up-appearances-with-adf-11g-richfaces-context-sensitive-styling-in-a-world-of-imperfect-html-with-dynamic-pagetemplate-and-page-fragment-includes.

The interesting part of course comes now:we  – or rather the UI team – decide that the UI pattern of table-with-detail-form should no longer be done with the form side by side with the table, but instead with the table above the form. And we could desire many more changes in either header/footer/sidebar (main template) or in the table-with-form UI pattern. For all of these changes holds: we apply the change in a single place, in the template, and all pages consuming the template will take over that change at run time.

The ADF 11g Area Template - for micro level layout design patterns productandpeoplepage templchange

Resources

Download the example project for this article: MultiTemplateApp.zip.

One Response

  1. shivaji September 7, 2011