Skip to content

Common Concepts 2.x

RomanPerin edited this page Aug 28, 2014 · 4 revisions

TOCSTART

TOCEND

Configuring Components

Kinds of Components, Component Names and API

There are both OpenFaces components that are the extended versions of the standard JSF components, and components which don't have their standard analogs. When creating the extended versions of the standard components we tended to minimize the efforts required for transition from the standard components to their OpenFaces analogs. Thus such components have the same name as their standard analogs, and the standard API is mostly preserved for them. In most cases, all that you're required to do to switch to the extended component, is to change the component's tag prefix. For example suppose you have the following declaration:

<h:commandButton value="Add" action="#{MyBean.add}"/>

<h:dataTable value="#{MyBean.users}" var="user"...> <f:column> ... </f:column> ... </h:dataTable>

All that you need to replace the standard components with their OpenFaces analogs is to use the "o:" tag prefix, without changing any other declarations, like this:

<o:commandButton value="Add" action="#{MyBean.add}"/>

<o:dataTable value="#{MyBean.users}" var="user"...> <o:column> ... </o:column> ... </o:dataTable>

Using OpenFaces analogs won't change the look and behavior of your components, though, once you've switched to using the OpenFaces versions of the standard components, you are free to use the vast range of the additional functionality. For example despite looking very similar to the standard <h:dataTable> tag and having a compatible API, the <o:dataTable> tag (which represents the OpenFaces DataTable component), provides an order of magnitute higher level of functionality as opposed to its standard version, with the features like sorting, selection, filtering, pagination, conditional styling, handling large data sets and much more.

In addition to the extended components, OpenFaces complements the standard components with a range of other components commonly required for web application development, such as containers, windows, calendars, charts, more input components, etc. Although not having analogs among the standard JSF components, we strived to make the API of all components as uniform as possible, so the approaches and functionality similar across several components usually have the similar API as well. As a result, you can learn a small part of the library and be fluent at using any other part of it. The sections below describe the concepts and approaches that are common for all OpenFaces components.

Customization With Attributes and Child Tags

As usual, the majority of customizations can be made through the attributes of the component's tag. The OpenFaces components have a set of common attributes. Similar to the standard JSF components, all OpenFaces components support the id, rendered and binding attributes. Input components support the required, validator and converter attributes. Most attributes allow specifying their values using the Expression Language (EL), and you can find out whether some particular attribute supports EL but looking up the Tag Reference.

OpenFaces also employs another powerful and flexible way of customization – a child tag based customization. This way of customization is usually applicable for complex component's features that cannot be controlled by just one attribute. For example you can add the row selection and scrolling capabilities to the <o:dataTable> component simply by adding the appropriate tags as follows:

<o:dataTable ...>
  <o:singleRowSelection rowData="#{MyBean.selectedRow}" style="background: silver"/>
  <o:scrolling horizontal="true" position="#{MyBean.tableScrollPos}/>
  ...
</o:dataTable>

This kind of customization usually serves two goals:

  • adding such tag tells the component that the appropriate functionality should be turned on;
  • having the tag allows customizing all of the aspects of the appropriate functionality in one place.
Customizing Styles

All OpenFaces components have a default style and allow flexible style customization through their attributes. These attributes usually define the component appearance in terms of Cascading Style Sheets (CSS) with a few exceptions mentioned explicitly in the documentation.

Every component has the style and styleClass attributes that control the style characteristics of the entire component. The style attribute is used to specify inline CSS declarations, and the styleClass attribute is used to reference CSS classes declared elsewhere on the page or attached to the page.

In case of complex components, you can usually customize styles for different parts of a component. The attributes that control a particular part of a component are named *Style and *Class, where the asterisk denotes the part of a component being customized, for example the DropDownField component has the buttonStyle/buttonClass attributes for customizing the style for its button.

There are also attributes that specify the style depending on the state of a particular part of the component. For example, rollover*Style, rollover*Class or pressed*Style, pressed*Class.

All styles that you specify for OpenFaces components are combined with the default component styles. The user-specified styles have a higher priority over the default ones, so if some style definitions overlap, custom styles will take the precedence.

When specifying the state-dependent styles, it is possible in certain cases that several styles at the same time can be considered applicable to a particular part of component. For example at a moment of pressing a button, the button's pressed style, rollover style and regular (no state) style is applicable. In such cases, all of the state-dependent styles applicable for the current state are applied and are merged with the usual CSS cascading rules according to styles' priorities. Here's how the state-dependent styles are typically separated into priorities (items below have a precedence over the items above):

  • Regular styles (e.g. style/styleClass, buttonStyle/buttonClass, etc.)
  • Rollover styles (rollover*Style and rollover*Class attributes).
  • Selected and pressed styles depending of the component (selected*Style and selected*Class / pressed*Style and pressed*Class attributes).
  • Disabled styles (disabled*Style and disabled*Class attributes).

Let's consider this on a simple example:

<o:inputText value="Test"
             style="font-size: 14pt; background: silver"
             rolloverStyle="background: yellow"/>

This component has a regular style of 14 pt font and a silver background, but when the mouse hovers over it, another style specifying the yellow background is added in addition to the regular style. Since both of the styles are applied simultaneously and a rollover style has a precedence over the regular style, hovering over the field will turn the background into yellow while retaining the font size specified in the regular style. The same is applicable for more complex scenarios when more styles can be applied simultaneously.

When creating the design for your application, please avoid relying on the HTML generated by components, since these are the internal implementation details, and can change either in response to different configuration parameters or different environment, or just as a result of normal process of component's evolution.
<p>Instead, OpenFaces ensures backwards compatibility in how component's appearance can be customized
    through its documented attributes, as described in this section above, so a proper approach to
    styling is to use the explicitly provided component's configuration attributes.</p>
Gridline/Separator Styles

Several components have another kind of style customization attributes. These are the attributes for customizing the style of lines that separate different component's parts, outline line styles, etc. For example the horizontalGridLines attribute of <o:dataTable> tag, or the frontBorderStyle attribute of the <o:tabbedPane> tag. These attributes specify are specified as values for the CSS border attribute but without the "border:" prefix, e.g. "1px solid gray". Here's an example:

<o:dataTable
    horizontalGridLines="1px solid #c0c0c0"
    verticalGridLines="1px solid gray"
    ...
OpenFaces and the Form component

Please note that in order for OpenFaces components to work properly, they should be placed into the <h:form> tag, or another analogous tag which renders the HTML <form> tag.

Handling Client-Side Events

All OpenFaces components have a set of standard client-side events, such as onclick, ondblclick, onfocus. In addition, some components provide non-standard client-side events whose functionality depends on a particular component.

Client-Side API

Some OpenFaces components provide client-side methods to control the state or behavior of a component on the client side. See the "Client-Side API" section in component documentation pages for a list of client-side functions available for the respective components. Each method listed in a "Client-Side API" section is a function that should be invoked on a component's instance. Component instance can be retrieved by component's client Id using the standard document.getElementById(id) functional, or the O$(id) function as described below.

The O$(id) Function

Retrieving HTML elements or JSF components by their client id is a very common scenario in client-side programming, which usually involves invoking the document.getElementById(id) function. OpenFaces introduces the O$(id) (capital letter O and a dollar sign) function as a short replacement for the document.getElementById(id) function. Here is an example of using this function for invoking the client-side show() function for a PopupLayer component:

<h:form id="form">
  <o:popupLayer id="popupLayer1">...</o:popupLayer>
  <h:commandButton value="Show" onclick="O$('form:popupLayer1').show(); return false;"/>
</h:form>

Note that the O$(id) function is undefined on pages that don't contain any OpenFaces components. If you'd like to have the O$(id) function on such pages anyway, you can declare the org.openfaces.forceIncludingUtilJs context parameter in application's web.xml file with a value of true:

<context-param>
  <param-name>org.openfaces.forceIncludingUtilJs</param-name>
  <param-value>true</param-value>
</context-param>

Client Action Components

There's a category of components that declare certain client-side behaviors that can be attached to other components or invoked explicitly with the JavaScript code. These are the components such as:

  • Confirmation which allows displaying a confirmation dialog prior to executing critical actions,
  • Ajax component, which allows adding Ajax interaction such as executing server code and reloading components upon the application-specific client-side events,
  • PopupMenu component, which can also serve as a client action component because it can be automatically attached to another component's "contextmenu" event.

All of the client action components can be used in the following three scenarios:

  • It's possible to place such component inside of the other component's tag and the appropriate client action will be automatically registered for that component. The parent component can be called an "action invoker component" in this case. The action will be invoked when the event specified with the client action's event attribute occurs on the invoker component. Omitting the event declaration results in attaching to the default event ("click" event for Confirmation and Ajax, and "contextmenu" event for PopupMenu). Here's an example:
    <h:inputText value="#{MyBean.value}">
      <o:ajax event="keyup" delay="500" render=":form:taskList :form:doneList :form:doneListCaption"/>
    <h:inputText>
    

    <h:commandButton value="Test" action="#{MyBean.test}"> <o:confirmation/> <!-- the default "click" event is implicitly used here --> </h:commandButton>

    <h:panelGrid> <o:popupMenu> <!-- the default "contextmenu" event is implicitly used here --> ... </o:popupMenu> ... </h:panelGrid>

    Note that evet names should be without the "on" prefix, for example "click" instead of "onclick".

  • It's possible to place the client action component anywhere on a page and attach it to the invoker component using the client action's for attribute as described below. The syntax for referring the components with the for attribute is the same as when using the for attribute of the standard <h:message> and <h:outputLabel> tags, and is the same as defined by the UIComponent.findComponent method. In short, you can either use the short relative id reference, e.g. for="myPanel" where myPanel is id of a component located in the same naming container as the client action, or you can use the absolute id reference which works regardless of where the action is positioned, for example for=":form:myPanel".
    <h:commandButton id="deleteButton" value="Delete" action="#{MyBean.delete}"/>
    <o:confirmation for="deleteButton"/>
    
  • It's possible to avoid attaching of the client action to another component for automatic invokation and utilize the standalone mode where an action can be invoked at any time explicitly with JavaScript. This can be done by specifying the standalone attribute with a value of true. The API of invoking the action explicitly depends on the client action component itself – refer to the respective documentation page. Here's an example that uses the standalone Ajax component:
    <o:ajax id="updateImage"
            standalone="true"
            render="dynamicImage"
            execute="textField colorField"
            delay="500"/>
    

    <h:inputText id="textField" onkeypress="O$('form:updateImage').run()" ... /> <h:selectOneMenu id="colorField" onchange="O$('form:updateImage').run()" .../>

    <o:dynamicImage id="dynamicImage" .../>

Please refer to the documentation for the appropriate client action components for the full information on their usage.

Ajax Support

Ajax is a technique providing the ability to exchange data with the server without reloading a Web page. As a result, Web applications provide smoother user interaction, better responsiveness and take less network traffic.

Please refer to the Ajax Framework page to learn about the Ajax capabilities provided with the OpenFaces library, and the way of utilizing various Ajax-related features such as reloading components, handling session expiration, customizing the Ajax progress message and defining Ajax-related events.

Creating Components Dynamically

You can create and manipulate OpenFaces components programmatically the same way as standard JSF components. However, there is one requirement: You should call the createSubComponents() method for some of the OpenFaces components after you create a component and configure its properties. This method should be called when dynamically creating the components that implement the org.openfaces.component.CompoundComponent interface after the component's id has been specified. These are components such as: FoldingPanel, TabbedPane, DropDownField, TableColumn, TreeColumn, ComboBoxFilter, DropDownFieldFilter, and InputTextFilter. Note that id assignment is optional, but the createSubComponents method should still be invoked along with dynamic component creation and component's id should not be changed after this invocation.

Here is an example of creating the TabbedPane component:

FacesContext facesContext = FacesContext.getCurrentInstance();
Application application= facesContext.getApplication();
TabbedPane tabbedPane = (TabbedPane) application.createComponent(TabbedPane.COMPONENT_TYPE);
tabbedPane.setId("myTabbedPane");
tabbedPane.setStyleClass("tabbedPane");
...
tabbedPane.createSubComponents(facesContext);

The Faces Utility Class

Take a look at the org.openfaces.util.Faces class, which contains some methods that can be useful for your JSF application development. You can implement the same operations yourself, but it can be very handy in some cases. Here are the most notable methods:

  • T var(Object varName, Class<T> expectedType) – returns the current value of the specified EL variable and casts it to the specified type. This method can particularly be useful when handling actions of components that reside in iterator components (e.g. DataTable, TreeTable, Timetable, etc.), to know the record for which the action was invoked. Of course it can be used not only with OpenFaces components, but in any case when you need to get some EL variable value from within your backing bean.
  • T requestParam(String paramName, Class<T> expectedType) – returns the value of the specified request parameter, and converts it from string to the specified type. This method is useful when processing parameters passed through link parameters.
  • T component(String clientId, Class<T> componentClass) – returns an instance of component with the specified client id. You can use it to avoid adding the binding attribute with a backing bean property, when you need easy access to component's Java API.

Open API

OpenFaces is a constantly evolving project and we strive to create a flexible and convenient API for the components and all capabilities provided by the library while not compromising API stability and backwards compatibility. There are different kinds of APIs in OpenFaces: tag-based APIs, Java APIs, and JavaScript APIs.

Please note that for Java and JavaScript APIs there are classes, methods and functions that are an internal part of OpenFaces and shouldn't be used from application code. Such classes and methods are not considered as a part of an "open API", which means that they can be changed as the project evolves and therefore no application code should use them. Though there's a safe criterion for judging whether a particular part of API is open – if a class, method or a JavaScript function is mentioned in this Developer's Guide, then it can be considered as an open API. Naturally, all component classes, all property accessors for any component's attribute, and all data types for those properties are considered an open API.

Please avoid using the JavaScript methods that are not listed in component documentation pages in this Developer's Guide.

Clone this wiki locally