Layout Pattern: Table with Header Left, Footer Right

An Oracle JDeveloper Best Practices Document
March, 2010

Pattern

Layout Pattern: Table with Header Left, Footer Right

Pattern Revision

1.0

Technologies

ADF Faces

Keywords

Header, Footer, Align

Forum

Pattern Team

Publish date

March 2010

Contents

Layout Description

This pattern describes a common scenario which can be applied at many levels from an area of the screen containing a table as illustrated here. It can also be applied to a complete page shell with similar characteristics. The basic requirements of the layout are:

  1. The table or similar content needs to be stretched to fill a specified container, for example, the whole browser window.
  2. The content needs to have a fixed header and footer with consistent heights.   The content will fill any available space not consumed by this header and footer
  3. The header area can contain a mix of components laid out horizontally, such as an image and text. This header area should be left aligned and vertically centered with a leading white space.
  4. The footer area also contains multiple components centered vertically, this time aligned to the right and with a trailing white space.
  5. Header and footer should be identically sized
  6. White space padding around the footer content should be consistent for the top, bottom and to the right of the content.
The following sketch illustrates the initial state of the layout:

Inital state of layout

The User Experience

When the surrounding container is resized then the following behaviors should be observed:

Resized Container
  1. Header picture and text retain their relationship and remain anchored to the top-left of the container with the appropriate white space. The height of the header remains constant
  2. Table (or other content) expands or contracts to take up any spare space in the container
  3. The components in the footer retain their relationship and stay anchored to the bottom-right of the container. The height of the footer, and white space to the top, bottom and right of the buttons remains constant.

Implementation

The construction of this layout consists of four layout containers defining three key elements:

The Core Layout

The core implementation for this pattern is a panelStretchLayout which provides the basic header, footer and content areas for the layout. The height of the header and footer will depend on your exact requirements, in this example we have calculated a height based on the height of the footer content buttons (19px) and the required padding (6px top and bottom):

Content Height px + (2 x padding px) = Required Height px

So in this case:

19px + (2 x 6px) = 31px

This result is applied to the panelStretchLayout:

<af:panelStretchLayout id="psl1"
bottomHeight="31px" topHeight="31px">

</ af:panelStretchLayout>

The Header Area

As the header content only has to flow horizontally in this case, we use a panelGroupLayout to enclose its content. This is placed in the top facet of the panelGroupLayout (pgl1) and basic alignment options defined:

<af:panelGroupLayout id="pgl1" halign="start" layout="horizontal" valign="middle">

</af:panelGroupLayout>

The content (an image and output text in this example) are then dropped into the panelGroupLayout, but because we want white space padding on the lead of the header area, first drop in a spacer. This spacer has a width of 6px (the required padding) and a height of 31. Setting the height of the spacer to the full required height of the header will ensure that the panelGroupLayout takes up the correct amount of vertical space and all of the other content will be centered vertically.

The Footer Area

The footer area is slightly more challenging because its content, in this example some buttons, needs to be aligned to the right hand bottom corner of the page. The parent panelStretchLayout provides the behavior to anchor the footer to the bottom of the container, however, to provide a flexible right alignment we have to nest another panelStretchLayout into the bottom facet of the main panelStretchLayout (psl1). The endwidth of this panelStretchLayout should be defined to be just large enough to contain the width of the content plus the required 6px terminating padding. In this case the result of that calculation is 103px:

<f:facet name=="bottom">

  <af:panelStretchLayout id="psl2" endWidth="103px">

 

  </af:panelStretchLayout>

</facet>

The footer contents will be placed in the end facet of this nested panelStretchLayout (psl2). As several components, including the padding need to be laid out horizontally a panelGroupLayout with the correct alignments is used to contain them. This time the padding needs to be to the right, so a spacer defined as 6x31 is dropped in as the last component in this panelGroupLayout:

<f:facet name="bottom">

  <af:panelStretchLayout id="psl2" endWidth="103px">

    <f:facet name="end">

      <af:panelGroupLayout layout="horizontal"

          id="pgl2" halign="end" valign="middle">

        <af:commandButton text="Save" id="cb1"/>

        <af:commandButton text="Cancel" id="cb2"/>

        <af:spacer width="6" height="31" id="s2"/>

      </af:panelGroupLayout>

    </f:facet>

  </af:panelStretchLayout>

</f:facet>

Note: Instead of setting a numeric demension for the endWidth,  "103px" in this instance, you can set the attribute to  "auto" to and the browser will determine the amount of space required to display the content in the facet. This can come in handy if you don't know ahead of time how much content is going in the footer area.

Logical View

The following diagram summarizes the way in which the containers are arranged:

Logical View

The Result

The following screenshots show the pattern in two implementations, firstly as the tenant of the top level browser window and secondly as a child of a stretching parent container:

Results

Results

Appendix - Complete Code

Complete Code

<af:panelStretchLayout id="psl1" bottomHeight="31px" topHeight="31px">

  <f:facet name="top">

    <af:panelGroupLayout halign="start" layout="horizontal"

                         valign="middle" id="pgl1">

      <af:spacer height="31" width="6" id="s1"/>

      <af:image source="/images/header_icon.png"

                shortDesc="Header Icon" id="i1"/>

      <af:outputText value="Header Text" id="ot1"

                     styleClass="AFBrandingBarTitle"/>

    </af:panelGroupLayout>

  </f:facet>

  <f:facet name="center">

 

  </f:facet>

  <f:facet name="bottom">

    <af:panelStretchLayout id="psl2" endWidth="103px">

      <f:facet name="end">

        <af:panelGroupLayout id="pgl2" layout="horizontal"

                             halign="end"

                             valign="middle">

          <af:commandButton text="Save" id="cb1"/>

          <af:commandButton text="Cancel" id="cb2"/>

          <af:spacer width="6" height="31" id="s2"/>

        </af:panelGroupLayout>

      </f:facet>

    </af:panelStretchLayout>

  </f:facet>

</af:panelStretchLayout>