Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1.4.0) B31973-06 |
|
![]() Previous |
![]() Next |
This chapter outlines the major ADF Faces architecture features and also provides information for using different features of the client-side architecture.
This chapter includes the following sections:
The ADF Faces rich client framework (RCF) provides many of the features you need to create AJAX-type functionality in your web application, all built into the framework. A key aspect of the RCF is the sparsely populated client-side component model. Client components exist only when they are required, either due to having a clientListener
handler registered on them, or because the page developer needs to interact with a component on the client side and has specifically configured the client component to be available.
The main reason client components exist is to provide an API contract for the framework and for developers. You can think of a client-side component as a simple property container with support for event handling. Because client components exist only to store state and provide an API, they have no direct interaction with the DOM (document object model) whatsoever. All DOM interaction goes through an intermediary called the peer. Most of the inner workings of the framework are hidden from you. Using JDeveloper in conjunction with ADF Faces, you can use many of the architectural features declaratively, without having to create any code.
For example, because RCF does not create client components for every server-side component, there may be cases where you need a client version of a component instance. Section 3.4, "Instantiating Client-Side Components," explains how to do this declaratively. You use the Property Inspector in JDeveloper to set properties that determine whether a component should be rendered at all, or simply be made not visible, as described in Section 3.8, "Understanding Rendering and Visibility."
Other functionality may require you to use the ADF Faces JavaScript API. For example, Section 3.5, "Locating a Client Component on a Page," explains how to use the API to locate a specific client-side component, and Section 3.6, "Accessing Component Properties on the Client," documents how to access specific properties.
The following RCF features are more complex, and therefore have full chapters devoted to them:
ADF Faces additions to the lifecycle: The ADF Faces framework extends the JSF lifecycle, providing additional functionality, including a client-side value lifecycle. For more information, see Chapter 4, "Using the JSF Lifecycle with ADF Faces."
Event handling: ADF Faces adheres to standard JSF event handling techniques. In addition, the RCF provides AJAX-based rich postbacks (called partial page rendering), as well as a client-side event model. For more information, see Chapter 5, "Handling Events."
Conversion and validation: ADF Faces input components have built-in capabilities to both convert and validate user entries. You can also create your own custom converters and validators. For more information, see Chapter 6, "Validating and Converting Input."
Partial page rendering: Partial page rendering (PPR) allows small areas of a page to be refreshed without the need to redraw the entire page. Many ADF Faces components have built-in PPR functionality. In addition, you can declaratively configure PPR so that an action on one component causes a rerender of another. For more information, see Chapter 7, "Rerendering Partial Page Content."
Geometry management: ADF Faces provides a number of layout components, many of which support geometry management by automatically stretching their contents to take up available space. For more information, see Chapter 8, "Organizing Content on Web Pages."
Messaging and help: The RCF provides the ability to display tooltips, messages, and help for input components, as well as the ability to display global messages for the application. The help framework allows you to create messages that can be reused throughout the application.You create a help provider using a Java class, a managed bean, an XLIFF file, or a standard properties file, or you can link to an external HTML-based help system. For more information, see Chapter 17, "Displaying Tips, Messages, and Help."
Hierarchical menu model: ADF Faces provides navigation components that render items such as tabs and breadcrumbs for navigating hierarchical pages. The RCF provides an XML-based menu model that, in conjunction with a metadata file, contains all the information for generating the appropriate number of hierarchical levels on each page, and the navigation items that belong to each level. For more information, see Chapter 18, "Working with Navigation Components."
Reusable components: The RCF provides three reusable building blocks that can be used by multiple pages in your application: page fragments that allow you to create a part of a page (for example an address input form); page templates that can provide a consistent look and feel throughout your application that can be updated with changes automatically propagating to all pages using the template; and declarative components that are composite components that developers can reuse, ensuring consistent behavior throughout the application. For more information, see Chapter 19, "Creating and Reusing Fragments, Page Templates, and Components."
Applying skins: The RCF allows you to create your own look and feel by creating skins used by the ADF Faces components to change their appearance. For more information, see Chapter 20, "Customizing the Appearance Using Styles and Skins."
Internationalization and localization: You can configure your JSF page or application to use different locales so that it displays the correct language based on the language setting of a user's browser. For more information, see Chapter 21, "Internationalizing and Localizing Pages."
Accessibility: ADF Faces components have built-in accessibility support for user agents, for example a web browser rendering to nonvisual media such as a screen reader or magnifier. Accessibility support also includes access keys that allow users to access components and links using only the keyboard, and audit rules that provide directions to create accessible images, tables, frames, forms, error messages, and popup dialogs using accessible HTML markup. For more information, see Chapter 22, "Developing Accessible ADF Faces Pages."
User-driven personalization: Many ADF Faces components, such as the panelSplitter
, allow users to change the display of the component at runtime. By default, these changes live only as long as the page request. However, you can configure your application so that the changes can be persisted through the length of the user's session. For more information, see Chapter 31, "Allowing User Customization on JSF Pages."
Drag and drop capabilities: The RCF allows the user to move (cut and paste), copy (copy and paste), or link (copy and paste as a link) data from one location to another. When the drop is completed, the component accepting the drop rerenders using partial page rendering. For more information, see Chapter 32, "Adding Drag and Drop Functionality."
The remainder of this chapter focuses on working with the client-side framework.
In a traditional JSF application, if you want to process events on the client, you must listen to DOM-level events. However, these events are not delivered in a portable manner. The ADF Faces client-side event model is similar to the JSF events model, but implemented on the client. The client-side event model abstracts from the DOM, providing a component-level event model and lifecycle, which executes independently of the server. Consequently, you do not need to listen for click
events on buttons. You can instead listen for AdfActionEvent
events, which can be caused by key or mouse events.
Events sent by clients are all subclasses of the AdfBaseEvent
class. Each client event has a source, which is the component that triggered the event. Events also have a type (for example, action
or dialog
), used to determine which listeners are interested in the event. You register a client listener on the component using the af:clientListener
tag.
For example, suppose you have a button that, when clicked, causes a "Hello World" alert to be displayed. You would first register a listener with the button that will invoke an event handler, as shown in Example 3-1.
Example 3-1 Registering a Client Listener
<af:commandButton text="Say Hello"> <af:clientListener method="sayHello" type="action"/> </af:commandButton>
Tip: Because the button has a registered client listener, the framework will automatically create a client version of the component. |
Next, implement the handler in a JavaScript function, as shown in Example 3-2.
When the button is clicked, because there is a client version of the component, the Adf
Action
client event is invoked. Because a clientListener
tag is configured to listen for the AdfAction
event, it causes the sayHello
function to execute. For more information about client-side events, see Section 5.3, "Using JavaScript for ADF Faces Client Events."
You can either add inline JavaScript directly to a page or you can import JavaScript libraries into a page. When you import libraries, you reduce the page content size, the libraries can be shared across pages, and they can be cached by the browser. You should import JavaScript libraries whenever possible. Use inline JavaScript only for cases where a small, page-specific script is needed.
Create and use inline JavaScript in the same way you would in any JSF application. Once the JavaScript is on the page, use a clientListener
tag to invoke it.
To use inline JavaScript:
Add the MyFaces Trinidad tag library to the root element of the page by adding the code shown in bold in Example 3-3.
Create the JavaScript on the page.
For example, the sayHello
function shown in Example 3-2 might be included in a JSF page as shown in Example 3-4.
Example 3-4 Inline JavaScript
<af:resource> function sayHello() { alert("Hello, world!") } </af:resource>
Note: Do not use thef:verbatim tag in a page or template to specify the JavaScript. |
In the Structure window, right-click the component that will invoke the JavaScript, and choose Insert inside component > ADF Faces > Client Listener.
In the Insert Client Listener dialog, in the Method field, enter the JavaScript function name. In the Type field, select the event type that should invoke the function.
Use the af:resource
tag to access a JavaScript library from a page. This tag should appear inside the document
tag's metaContainer
facet.
To access a JavaScript library from a page:
Below the document
tag, add the code shown in bold in Example 3-5 and replace /mySourceDirectory
with the relative path to the directory that holds the JavaScript library.
In the Structure window, right-click the component that will invoke the JavaScript, and choose Insert inside component > ADF Faces > Client Listener.
In the Insert Client Listener dialog, in the Method field, enter the fully qualified name of the function. For example, if the sayHello
function was in the MyScripts
library, you would enter MyScripts.sayHello
. In the Type field, select the event type that should invoke the function.
Often when your JavaScript needs to access a client, it is within the context of a listener and must access the event's source component. Use the getSource()
method to get the client component. Example 3-6 shows the sayHello
function accessing the source client component in order to display its name.
Example 3-6 Accessing a Client Event Source
function sayHello(actionEvent) { var component=actionEvent.getSource(); //Get the ID for the component var id=component.getId alert("Hello from "+id); }
For more information about accessing client event sources, see Section 5.3, "Using JavaScript for ADF Faces Client Events." For more information about accessing client-side properties, see Section 3.6, "Accessing Component Properties on the Client." For a complete description of how client events are handled at runtime, see Section 5.3.6, "What Happens at Runtime: How Client-Side Events Work."
The RCF does not make any guarantees about which components will have corresponding client-side component instances by default. You will usually interact with client-side components by registering a clientListener
handler. When a component has a registered clientListener
handler, it will automatically have client-side representation. If you have to access another component on the client, then explicitly configure that component to be available on the client by setting the clientComponent
attribute to true
.
When you set the clientComponent
attribute to true
, the framework creates an instance of an AdfUIComponent
class for the component. This class provides the API that you can work with on the client side and also provides basic property accessor methods (for example, getProperty()
and setProperty()
), event listener registration, and event delivery-related APIs. The framework also provides renderer-specific subclasses (for example, AdfRichOutputText
) which expose property-specific accessor methods (for example, getText()
and setText()
). These accessor methods are simply wrappers around the AdfUIComponent
class's getProperty()
and setProperty()
methods and are provided for coding convenience.
For example, suppose you have an outputText
component on the page that will get its value (and therefore the text to display) from the sayHello
function. That function must be able to access the outputText
component in order to set its value. For this to work, there must be a client-side version of the outputText
component. Example 3-7 shows the JSF page code. Note that the outputText
component has an id
value and the clientComponent
attribute is set to true
. Also, note there is no value in the example, because that value will be set by the JavaScript.
Example 3-7 Adding a Component
<af:commandButton text="Say Hello"> <af:clientListener method="sayHello" type="action"/> </af:commandButton> <af:outputText id="greeting" value="" clientComponent="true">
Because the outputText
component will now have client-side representation, the JavaScript will be able to locate and work with it.
When you need to find a client component that is not the source of an event, you can use the AdfUIComponent.findComponent(expr)
method. This method is similar to the JSF UIComponent.findComponent()
method, which searches for and returns the UIComponent
object with an ID that matches the specified search expression. The AdfUIComponent.findComponent(expr)
method simply works on the client instead of the server.
Example 3-8 shows the sayHello
function finding the outputText
component using the component's ID.
Example 3-8 Finding a Client Component Using findComponent()
function sayHello(actionEvent) { var component=actionEvent.getSource(); //Find the client component for the "greeting" af:outputText var greetingComponent=component.findComponent("greeting"); //Set the value for the outputText component greetingComponent.setValue("Hello World") }
Instead of using the AdfUIComponent.findComponent(expr)
method, you can use the AdfPage.PAGE.findComponentByAbsoluteId(absolute expr)
method when you know the absolute identifier for the component, but you don't have a component instance to call AdfUIComponent.findComponent(expr)
on. AdfPage.PAGE
is a global object that provides a static reference to the page's context object. However, if the component you are finding is within a naming container, then you must use AdfUIComponent.findComponent
. For more information, see Section 3.5.1, "What You May Need to Know About Finding Components in Naming Containers."
Note: There is also a confusingly namedAdfPage.PAGE.findComponent(clientId) method, however this function uses implementation-specific identifiers that can change between releases and should not be used by page authors. |
If the component you need to find is within a component that is a naming container (such as pageTemplate
, subform
, table
, and tree
), then instead of using the AdfPage.PAGE.findComponentByAbsoluteId(absolute expr)
method, use the AdfUIComponent.findComponent(expr)
method. The expression can be either absolute or relative.
Tip: You can determine whether or not a component is a naming container by reviewing the component tag documentation. The tag documentation states whether a component is a naming container. |
Absolute expressions use the fully qualified JSF client ID (meaning, prefixed with the IDs of all NamingContainer
components that contain the component) with a leading NamingContainer.SEPARATOR_CHAR
character, for example:
":" + (namingContainersToJumpUp * ":") + some ending portion of the clientIdOfComponentToFind
For example, to find a table whose ID is t1
that is within a panel collection component whose ID is pc1
contained in a region whose ID is r1
on page that uses the myTemplate
template, you might use the following:
:myTemplate:r1:pc1:t1
Alternatively, if both the components (the one doing the search and the one being searched for) share the same NamingContainer
component somewhere in the hierarchy, you can use a relative path to perform a search relative to the component doing the search. A relative path has multiple leading NamingContainer.SEPARATOR_CHAR
characters, for example:
":" + clientIdOfComponentToFind
In the preceding example, if the component doing the searching is also in the same region as the table, you might use the following:
::somePanelCollection:someTable
Tip: Think of a naming container as a folder and theclientId as a file path. In terms of folders and files, you use two sequential periods and a slash (../) to move up in the hierarchy to another folder. This is the same thing that the multiple colon (:) characters do in the findComponent() expression. A single leading colon (:) means that the file path is absolute from the root of the file structure. If there are multiple leading colon (:) characters at the beginning of the expression, then the first one is ignored and the others are counted, one set of periods and a slash (../ ) per colon (:) character. |
When deciding whether to use an absolute or relative path, keep the following in mind:
If you know that the component you are trying to find will always be in the same naming container, then use an absolute path.
If you know that the component performing the search and the component you are trying to find will always be in the same relative location, then use a relative path.
There are no getChildren()
or getFacet()
functions on the client. Instead, the AdfUIComponent.visitChildren()
function is provided to visit all children components or facets (that is all descendents). See the ADF Faces JavaScript documentation for more information.
For each built-in property on a component, convenience accessor methods are available on the component class. For example, you can call the getValue()
method on a client component and receive the same value that was used on the server.
Note: All client properties in ADF Faces use thegetXyz function naming convention including boolean properties. The isXyz naming convention for boolean properties is not used. |
Constants are also available for the property names on the class object. For instance, you can use AdfRichDialog.STYLE_CLASS
constant instead of using "styleClass
".
Note: In JavaScript, it is more efficient to refer to a constant than to code the string, as the latter requires an object allocation on each invocation. |
When a component's property changes, the end result should be that the component's DOM is updated to reflect its new state, in some cases without a roundtrip to the server. The component's role in this process is fairly limited: it simply stores away the new property value and then notifies the peer of the change. The peer contains the logic for updating the DOM to reflect the new component state.
As noted in Section 1.2.2, "ADF Faces Architectural Features," most property values that are set on the client result in automatic synchronization with the server (although some complex Java objects are not sent to the client at all). There are however, two types of properties that act differently: secured properties and disconnected properties.
Secured properties are those that cannot be set on the client at all. For example, say a malicious client used JavaScript to set the immediate
flag on a commandLink
component to true
. That change would then be propagated to the server, resulting in server-side validation being skipped, causing a possible security hole (for more information about using the immediate
property, see Section 4.2, "Using the Immediate Attribute"). Consequently, the immediate
property is a secured property.
Attempts to set any other secured property from JavaScript will fail. For more information, see Section 3.6.2, "How to Unsecure the disabled Property." Table 3-1 shows the secure properties on the client components.
Table 3-1 Secure Client Properties
Component | Secure Property |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADF Faces does allow you to configure the disabled
property so that it can be made unsecure. This can be useful when you need to use JavaScript to enable and disable buttons. When you set the unsecure
property to true
, the disabled
property (and only the disabled
property) will be made unsecure.
Disconnected properties are those that can be set on the client, but that do not propagate back to the server. These properties have a lifecycle on the client that is independent of the lifecycle on the server. For example, client form input components (like AdfRichInputText
) have a submittedValue
property, just as the Java EditableValueHolder
components do. However, setting this property does not directly affect the server. In this case, standard form submission techniques handle updating the submitted value on the server.
A property can be both disconnected and secured. In practice, such properties act like disconnected properties on the client: they can be set on the client, but will not be sent to the server. But they act like secured properties on the server, in that they will refuse any client attempts to set them.
The RCF provides setXYZ
convenience functions that provide calls to the AdfUIComponent
setProperty()
function. The setProperty()
function takes the following arguments:
Property name (required)
New value (required)
You use the unsecured
property to set the disabled
property to be unsecure. You need to manually add this property and the value of disabled
to the code for the component whose disabled
property should be unsecure. For example, the code for a button whose disabled
property should be unsecured would be:
<af:commandButton text="commandButton 1" id="cb1" unsecure="disabled"/>
Once you set the unsecure
attribute to disabled
, a malicious JavaScript could change the disabled
attribute unwittingly. For example, say you have an expense approval page, and on that page, you want certain managers to be able to only approve invoices that are under $200. For this reason, you want the approval button to be disabled unless the current user is allowed to approve the invoice.
If you did not set the unsecured
attribute to disabled
, the approval button would remain disabled until a round-trip to the server occurs, where logic determines if the current user can approve the expense. But because you want the button to display correctly as the page loads the expense, say you set the unsecure
attribute to disabled
. Now you can use JavaScript on the client to determine if the button should be disabled. But now, any JavaScript (including malicious JavaScript that you have no control over) can do the same thing.
To avoid this issue, you must ensure that your application still performs the same logic as if the round-trip to the server had happened. In the expense report approval screen, you might have JavaScript that checks that the amount is under $200, but you still need to have the action for the approval button perform the logic on the server. Adding the logic to the server ensures that the disabled attribute does not get changed when it should not.
Similarly, if you allow your application to be modified at runtime, and you allow users to potentially edit the unsecure
and/or the disabled
attributes, you must ensure that your application still performs the same logic as if the round-trip to the server had occurred.
Calling the setProperty()
function on the client sets the property to the new value, and synchronously fires a PropertyChangeEvent
event with the new values (as long as the value is different). Also, setting a property may cause the component to rerender itself.
In some cases you may want to send additional information to the client beyond the built-in properties. This can be accomplished using bonus attributes. Bonus attributes are extra attributes that you can add to a component using the clientAttribute
tag. For performance reasons, the only bonus attributes sent to the client are those specified by clientAttribute
.
The clientAttribute
tag specifies a name/value pair that is added to the server-side component's attribute map. In addition to populating the server-side attribute map, using the clientAttribute
tag results in the bonus attribute being sent to the client, where it can be accessed through the AdfUIComponent.getProperty("
bonusAttributeName
")
method.
The RCF takes care of marshalling the attribute value to the client. The marshalling layer supports marshalling of a range of object types, including strings, booleans, numbers, dates, arrays, maps, and so on. For more information on marshalling, see Section 5.4.3, "What You May Need to Know About Marshalling and Unmarshalling Data."
Performance Tip: In order to avoid excessive marshalling overhead, use client-side bonus attributes sparingly. |
Note: TheclientAttribute tag should be used only for bonus (application-defined) attributes. If you need access to standard component attributes on the client, instead of using the clientAttribute tag, simply set the clientComponent attribute to true . For more information, see Section 3.4, "Instantiating Client-Side Components." |
You can use the Component Palette to add a bonus attribute to a component.
In the Structure window, select the component to which you would like to add a bonus attribute.
In the Component Palette, from the Operations panel, drag and drop a Client Attribute as a child to the component.
In the Property Inspector, set the Name and Value attributes.
Although client-side bonus attributes are automatically delivered from the server to the client, the reverse is not true. That is, changing or setting a bonus attribute on the client will have no effect on the server. Only known (nonbonus) attributes are synchronized from the client to the server. If you want to send application-defined data back to the server, you should create a custom event. For more information, see Section 5.4, "Sending Custom Events from the Client to the Server."
All ADF Faces display components have two attributes that relate to whether or not the component is displayed on the page for the user to see: rendered
and visible
.
The rendered
attribute has very strict semantics. When rendered
is set to false
, there is no way to show a component on the client without a roundtrip to the server. To support dynamically hiding and showing page contents, the RCF adds the visible
attribute. When set to false
, the component's markup is available on the client but the component is not displayed. Therefore calls to the setVisible(true)
or setVisible(false)
method will, respectively, show and hide the component within the browser (as long as rendered
is set to true
), whether those calls happen from Java or from JavaScript.
Example 3-9 shows two outputText
components, only one of which is rendered at a time. The first outputText
component is rendered when no value has been entered into the inputText
component. The second outputText
component is rendered when a value is entered.
Example 3-9 Rendered and Not Rendered Components
<af:panelGroupLayout layout="horizontal"> <af:inputText label="Input some text" id="input" value="#{myBean.inputValue}"/> <af:commandButton text="Enter"/> </af:panelGroupLayout> <af:panelGroupLayout layout="horizontal"> <af:outputLabel value="You entered:"/> <af:outputText value="No text entered" id="output1" rendered="#{myBean.inputValue==null}"/> <af:outputText value="#{myBean.inputValue}" rendered="#{myBean.inputValue !=null}"/> </af:panelGroupLayout>
Provided a component is rendered in the client, you can either display or hide the component on the page using the visible
property.
Example 3-10 shows how you might achieve the same functionality as shown in Example 3-9, but in this example, the visible
attribute is used to determine which component is displayed (the rendered
attribute is true
by default, it does not need to be explicitly set).
Example 3-10 Visible and Not Visible Components
<af:panelGroupLayout layout="horizontal"> <af:inputText label="Input some text" id="input" value="#{myBean.inputValue}"/> <af:commandButton text="Enter"/> </af:panelGroupLayout> <af:panelGroupLayout layout="horizontal"> <af:outputLabel value="You entered:"/> <af:outputText value="No text entered" id="output1" visible="#{myBean.inputValue==null}"/> <af:outputText value="#{myBean.inputValue}" visible="#{myBean.inputValue !=null}"/> </af:panelGroupLayout>
However, because using the rendered
attribute instead of the visible
attribute improves performance on the server side, you may instead decide to have JavaScript handle the visibility.
Example 3-11 shows the page code for JavaScript that handles the visiblity of the components.
Example 3-11 Using JavaScript to Turn On Visibility
function showText() { var output1 = AdfUIComponent.findComponent("output1") var output2 = AdfUIComponent.findComponent("output2") var input = AdfUIComponent.findComponent("input") if (input.getValue() == "") { output1.setVisible(true); } else { output2.setVisible(true) } }
You can create a conditional JavaScript function that can toggle the visible
attribute of components.
To set visibility:
Create the JavaScript that can toggle the visibility. Example 3-11 shows a script that turns visibility on for one outputText
component if there is no value; otherwise, the script turns visibility on for the other outputText
component.
For each component that will be needed in the JavaScript function, expand the Advanced section of the Property Inspector and set the ClientComponent
attribute to true
. This creates a client component that will be used by the JavaScript.
For the components whose visibility will be toggled, set the visible
attribute to false
.
Example 3-12 shows the full page code used to toggle visibility with JavaScript.
Example 3-12 JavaScript Toggles Visibility
<f:view> <af:resource> function showText() { var output1 = AdfUIComponent.findComponent("output1") var output2 = AdfUIComponent.findComponent("output2") var input = AdfUIComponent.findComponent("input") if (input.value == "") { output1.setVisible(true); } else { output2.setVisible(true) } } </af:resource> <af:document> <af:form> <af:panelGroupLayout layout="horizontal"> <af:inputText label="Input some text" id="input" value="#{myBean.inputValue}" clientComponent="true" immediate="true"/> <af:commandButton text="Enter" clientComponent="true"> <af:clientListener method="showText" type="action"/> </af:commandButton> </af:panelGroupLayout> <af:panelGroupLayout layout="horizontal"> <af:outputLabel value="You entered:" clientComponent="false"/> <af:outputText value="No text entered" id="output1" visible="false" clientComponent="true"/> <af:outputText value="#{myBean.inputValue}" id="output2" visible="false" clientComponent="true"/> </af:panelGroupLayout> </af:form> </af:document> </f:view>
If the parent of a component has its visible
attribute set to false
, when the isVisible
function is run against a child component whose visible
attribute is set to true
, it will return true
, even though that child is not displayed. For example, say you have a panelGroupLayout
component that contains an outputText
component as a child, and the panelGroupLayout
component's visible
attribute is set to false
, while the outputText
component's visible
attribute is left as the default (true
). On the client, neither the panelGroupLayout
nor the outputText
component will be displayed, but if the isVisible
function is run against the outputText
component, it will return true
.
For this reason, the RCF provides the isShowing()
function. This function will return false
if the component's visible
attribute is set to false
, or if any parent of that component has visible
set to false
.