Friday, August 28, 2009

ADF Layout Overview and Best Practices

Creating custom applications in Oracle JDeveloper using the Oracle Webcenter framework can be quite productive using the included out-of-the box components, taskflows and services. However, when it come to designing the page UI, it can be a frustrating experience. This is due in part on how certain components interact with each other in terms of flow and/or the ability to stretch its contents. In the beginning, I learned how to "get along" with working with the layouts components through many trial and error experiences. Basically, there are some general guidelines and best practices that you need to follow so that your UI design exhibits its entended behavour:
  • Never try to stretch something vertically when inside of a flowing (non-stretched) container. If you attempting to do this, the result will exhibit inconsistent behavior across web browsers.
  • Never specify a height value with percent units. Instead, define such stretching declaratively as by following the process outlined below.
  • Never use the "position" style.
  • Create a stretchable outer frame. Build up the outer structure of your page using a structure of components that support being stretched and also stretch their children.
    Each layout or panel component's tag documentation will identify whether this is supported and how to achieve it in its "Geometry Management" documentation. Some components have attributes to determine whether children will be stretched or not. For example: "document" has its maximized attribute, "showDetailItem" has its stretchChildren attribute. Typically you would use various combinations of the decorativeBox, panelSplitter and panelStretchLayout components inside of your document component to create the stretchable outer frame.
  • Consider using pageTemplates, declarative components, and regions for reuse and centralized maintenance.
  • Create flowing islands. Inside of the stretchable structure created in step 1, create islands of flowing (non-stretched) components. To make this transition from stretching to flowing, use panelGroupLayout with layout="scroll" since it supports being stretched but will not stretch its children.
  • Do not attempt to stretch anything vertically inside of these flowing islands.
  • Many leaf components do not make sense by themselves. For example, if you have a series of input components, you would never want to just place these in a panelGroupLayout because it would be much better for usability if you placed them in a panelFormLayout so the labels and fields would line up.
  • A sample list of components that cannot be reliably stretched includes: Most input components, panelBorderLayout, panelFormLayout, panelGroupLayout (with layout="default") , panelGroupLayout (with layout="horizontal"), panelHeader (with type="flow"), panelLabelAndMessage, panelList, Apache MyFaces Trinidad HTML Component - tableLayout, and JSF HTML Component - panelGrid.
  • Use themed decorativeBox components to organize your page layers with visual distinction and decorative borders as seen in some of the sample skins. Note that not all skins have alternative themes so you may not see any distinction. If your decorativeBox components are not showing up with different colored backgrounds and you know that you are using a skin that has definitions for alternate themes, you might be missing a web.xml context-param setting for "oracle.adf.view.rich.tonalstyles.ENABLED" being set to false. Your document component also has a theme attribute so you can use it to change the main background styling of your page.
  • Use a custom skin for consistently modified appearances if the existing skin doesn't provide all that you need. For instance-specific alternative styling, use the styleClass attribute. Keep the corresponding style definitions in an easy-to-maintain location such as in a custom skin, in the metaContainer facet of the document component, or in a style provided by the resource tag.

As a last resort, use the component attributes such as inlineStyle, contentStyle, and labelStyle. These are less declarative, harder to maintain, contribute more to the page's raw HTML size, and may not even be needed if one or more of the above mechanisms are used.
Styles are directly processed by the web browser which gives you a great deal of power but at the cost of being less declarative and error-prone. The browsers do not support all styles on all elements and certain combinations of styles produce non-obvious results.

Here is some guidance on style configurations to avoid on all components:

  • An inlineStyle with a "height" value with "%" units
  • An inlineStyle with a "width" value between "90%" and "100%" (use styleClass="AFStretchWidth" or styleClass="AFAuxiliaryStretchWidth" instead)
  • An inlineStyle with "height", "top", and "bottom" values
  • An inlineStyle with "width", "left", and "right" values
  • An inlineStyle with a "position" value

Here is some guidance on style configurations to avoid on a Child component being stretched by a Parent component :

  • An inlineStyle with "width" or "height" values

Scrolling:

  • You should only have scrollbars around flowing island content. The recommended transition component for switching from a stretching outer frame into a flowing island is the panelGroupLayout with layout="scroll". If the contents of this panelGroupLayout cannot fit in the space allocated, the browser will determine whether scrollbars are needed and will add them automatically.
  • It is not recommended that you nest scrolling panelGroupLayout components because this will make the user see multiple scrollbars. Also, this should only be used at transitions from stretching to flowing areas and since you should not have stretching areas inside of flowing areas, you would generally never end up with nested scrollbars. It is best to minimize the number of areas that a user must scroll in order to see what he or she is looking for. Take time to consider what scrolling the user will need. In cases where undesired scrollbars exist, you may want to simply change the layout attribute of that panelGroupLayout to "vertical".
  • There is a known scrolling issue that has been filed against Internet Explorer 7.0.5730.11. The issue is only resolved in Internet Explorer 8 when running in pure IE8 rendering mode. If a scrolling box has contents that are set to be as wide as the containing box and if the contents are large enough to warrant the need for a vertical scrollbar, an unnecessarily-needed horizontal scrollbar will be added. The browser is failing to adjust the width of the contents for the presence of the vertical scrollbar and thus a horizontal scrollbar appears. This horizontal scrollbar lets you scroll the small amount of space equal to the width of the vertical scrollbar. With this issue, it is not recommended to specify a width anywhere between 90% and 100%. Smaller widths will generally not encounter the bug. Workarounds (as seen in this page) involve setting the widths of the contents to be smaller than full width so that the browser has enough space for a vertical scrollbar to fit. For your convenience, a styleClass named "AFStretchWidth" is built into the skin to specify that a component with this styleClass will get a reduced width in Internet Explorer 7 or full width in other browsers. If you need a smaller size for an thin auxiliary column, you can alternatively use "AFAuxiliaryStretchWidth" or you may create a similar skin definition in your own skin like this:

@agent ie and (version: 7.0) {
.AFIEOverflowWorkaround75 { width: 75%; }
}

Margins, borders, padding:

  • Thanks to the browser's "CSS Box Model rules", it is much harder to define margins, borders, and padding on your components than what you might expect. In many cases, to apply these kinds of styles, you need to use multiple components together. In a scrolling area, adding an extra panelGroupLayout with layout="vertical" with the padding defined on it inside of the outer layout="scroll" panelGroupLayout will be required. In a stretching area, you may need to wrap a component inside of a panelStretchLayout with spacers in its top, start, end, and bottom facets for the padding.

10 comments:

  1. Hi Martin,

    This article is really helpful.

    I have one small query on the browser scrolling. I am using panelstretchlayout to keep my web contents in the center section and keeping rest of the sections a blank. I have paneltabbed in the center section. But now I am facing scrolling issues and I am not getting any scroll bars if I resize my window.

    Please suggest here.

    Thanks,
    Kamleshwar

    ReplyDelete
  2. Hi Kamleshwar,

    You can surround the paneltabbed component with a panelgrouplayout (set to "scroll"), to get the scrollbars. Also ensure that the panelgrouplayout is the only child of the center facet of the panelstretchlayout.

    ReplyDelete
  3. Good articles Martin - keep up the great work :)

    ReplyDelete
  4. This is a great article. I am a former main framer currently programming Peoplesoft and I am teaching myself JDeveloper as I believe it is the direction Oracle is headed. I hope to one day find a job using this fantastic tool.

    ReplyDelete
  5. Hi ,
    I have a panel GroupLayout with a form and a panel collection .
    Panel collection has a commandlink in its tool bar facet and a table .
    When i click on the command link t doesnot validate the mandatory fields of the form in GroupLayout.
    The same command link when placed outside the panel-collection validates all the fields as required.
    Can any one explain the difference and tell me how to validate the form field still using the command link in toolbar facet of panel collection

    ReplyDelete
  6. Here I've described a simple method to achieve complex layouts.
    http://adfpractice-sokol.blogspot.com/2012/06/complex-forms-simple-and-easy.html

    ReplyDelete
  7. Hi,
    I have a tree table which has only 13 master nodes to show and it should initially not be expanded. I see that the rows dont cover the entire area of the table, there is a blank area underneath the rows. I somehow want the table to adjust the rendered rows, so that the blank area is also covered. I have attached the screenshot of the ugly blank area within the table.
    http://oi48.tinypic.com/v4ba5y.jpg

    The hierarchy of components used is
    af:group

    |___af:panelTabbed

    |______af:showdetailItem

    |______af:panelHeader

    |____af:panelSplitter

    |____af:panelSplitter

    |_____af:panelCollection

    |______af:treeTable

    Can you please let me know as to how to get rid of this unused blank area.

    Thanks,
    Divya.

    ReplyDelete
  8. Hi Martin Deh,

    Really Very Good Article.
    I have a query on the stretching of PannelTabbed Component. i.e., I have a surround pannelTabbed (Child) component with a PanelCaptionGroup (Parent).
    I want to display PanelTabbed component without any scrollbars if the contents of PanelTabbed content exceeds the limit.
    Actually Internet Explorer 6 stretches the panelTabbed component without any issues and the contents are getting displayed properly whereas the higher versions are not supporting the stretching of Paneltabbed component.
    Could you please tell me how to stretch PanelTabbed component if the contents exceeds the limit?

    Thanks and Regards,
    Krishna

    ReplyDelete
  9. Thanks for posting the blog. I felt comfortable while reading the post. Keep posting more blogs.

    Manual Testing Training in Dallas

    Manual Testing Training in Dallas

    ReplyDelete