Quantcast
Channel: Oracle Bloggers
Viewing all articles
Browse latest Browse all 19780

Building the revealPanel - Part 1

$
0
0
Working with one of our internal teams the other day, a couple of interesting ideas came up for presenting information. One of these was a sort of twist on panelAccordion and it seems to be a nice usecase to work through to show how you can get creative with your UI without having to ask for and wait for new components. 

The Brief

As I said, the requirement here was to produce something like panelAccordion. However, rather than restricting the selection bar to just a single line of text an maybe an icon,  what if you wanted larger images or multiple lines?  Here's a mockup:



Then like a panelAccordion, with discloseMany="false" and discloseNone="true" you want to be able to expand the details of up to one and only one of the selection panels (I'll call them "Topics" from now on).



So if I click anywhere in the first topic bar in the above image then that topic will collapse, if I click on a different topic bar then the first will collapse and the new selection will expand.
You'll notice the modernist conceit of the little triangle linking the revealed panel with it's topic. It's a small thing but that also helps to polish the look and make it feel current.

The UI Elements

So how would we build this? Well the answer is that the UI itself is surprisingly easy. That's all thanks to our new friend, the panelGridLayout which hands us everything we need on a plate. 
We can break down the mockup above into three sets of repeating units, remember I called them topics.  Each topic is identical, so let's just look at one.
Logically the topic is composed of three vertically arranged areas:

(1) The topic header itself
        |
(2) The little indicator triangle
        |
(3) The reveal panel area with the additional content 

Area 1, the header is always displayed and areas 2 and 3 we need to reveal or hide dynamically when the user clicks anywhere on area 1.
In panelGridLayout terms we can simply translate this into three grid rows, one for each area.  The key point here is that if you set the height attribute of a <af:gridRow> to the value "auto" the grid will automatically size that row to fit its children, so guess what: if we set visible="false" on the contents in areas 2 and 3 then the grid shrinks for free. I just love that this is so easy.
So here's the outline component model for a revealPanel (Yes there is a full demo you can download - read on to the end)

<panelGridLayout><!-- For Each Topic -->  <gridRow height="50px">    <gridCell columnSpan="3" halign="stretch">      <panelGroupLayout layout="vertical" styleClass="revealTopicPanel">      <!-- Topic header content will go here -->       <panelGroupLayout>    </gridCell>  </gridRow>  <gridRow height="auto">    <gridCell width="80px"/>    <gridCell width="10px" valign="bottom">      <panelGroupLayout layout="vertical"                         styleClass="triangleMarker"/>    </gridCell>    <gridCell width="100%"/>  </gridRow>  <gridRow height="auto">    <gridCell columnSpan="3" halign="stretch">      <panelGroupLayout styleClass="revealPanel"      <!-- Revealed content will go here -->     </gridCell>  </gridRow></panelGridLayout>

Let's look at the key points
  1. The first grid row representing the topic header can be fixed in size to make sure that the unexpanded list is regular.
  2. The first grid row just contains a single grid cell that streches across three logical cells using the columnSpan attribute. The reason for doing this will become clear when we look at the second area of the topic 
  3. We use halign="stretch" on that first area gridCell to fill it with its content. This is important to make the included component (e.g. panelGroupLayout in this case) fill the cell with its styling.
  4. Moving onto the second area of the topic than contains the little indicator triangle, here the row as it's height as auto so it will collapse when we hide the triangle.
  5. The triangle area row is divided into three cells. The center cell contains the actual triangle (see below) and the other two cells are used to position the triangle cell to a particular horizontal position. In this case I'm indenting the triangle by a fixed 80 pixels, however, if I adjusted the first and last cells to use width="50%" then the triangle would be centered to the width of the panel.
  6. The final area is again a grid row with height set to auto containing a single cell with columnSpan set to 3 and stretching it's content. 

The Triangle

The little triangle indicator could be done using an image file, however, here I'm just using a CSS style which is simpler and enables you to change the color as required. Here's the definition:

 .triangleMarker {  width:0px;  height:0px;  border-left:8px solid transparent;  border-right:8px solid transparent;  border-bottom:8px solid rgb(247,255,214);  
}
This style is applied to the vertical panelGridLayout in the center area.  Vertical panelGrids become simple html <div> elements.

Managing the Topic - The Server Side Version

I'll cover a more advanced version of the component in my next posting which uses JavaScript to manage the hide and reveal of the panels, but in this post, let's look at the simple version. 
As discussed, the paneLGridLayout actually does all of the UI resizing for us, so all we really need to do to manage the set of topics is two things:
  1. Introduce a management class that will tell the reveal panel and triangle panel if they should be visible or not
  2. A small amount of event code to translate a click anywhere on the topic panel into a change in the above management class. 

The Management Class

For the sake of the demo I've developed a very simple management class that does not attempt to do anything fancy such as handling multiple sets of revealPanels (that task is left for the JavaScript implementation). Here's the class:

package oracle.demo.view;
import java.util.ArrayList;
import java.util.List;
public class RevealPanelManager {    private int _panelCount = 10;    private int _toggleTarget = -1;    private List<Boolean> _revealedList;    /**     * Switches the state of the currently selected panel      */    public void toggleState() {        if (_toggleTarget >= 0 && _panelCount > 0) {            boolean currentState = false;            if (_revealedList != null){                currentState = _revealedList.get(_toggleTarget);            }            resetStates();            if (!currentState) {                _revealedList.set(_toggleTarget, true);            }            _toggleTarget = -1;        }    }    /**     * Used to inject a panelCount into the management structure. If not called then an array upper limit of      * 10 will be used     * @param panelCount     */    public void setPanelCount(Long panelCount) {        int candidateCount = panelCount.intValue();        if (candidateCount > 0) {            //reset the list & re-create in the new size            _revealedList = null;            _panelCount = candidateCount;            resetStates();            }    }    /**     * Invoked, probably from a setPropertyListener / setActionListener to set the id of the      * panel to act on.  This may disclose or hide depending on the current state of the selected     * panel     * @param toggleNo - index number of the panel     */    public void setToggleTarget(int toggleNo) {        this._toggleTarget = toggleNo;    }    /**     *Called by the panel to see if it should be visible or not     * @return List of Booleans indexed by panel number     */    public List<Boolean> getRevealed() {        return _revealedList;    }    /**     * Either creates or reinitializes the array to close all the      * panels     */    private void resetStates() {        if (_revealedList == null) {            _revealedList = new ArrayList<Boolean>(_panelCount);            for (int i=0; i < _panelCount; i++) {              _revealedList.add(i,false);            }        }        else{            for (int i = 0; i < _panelCount; i++) {                _revealedList.set(i, false);            }                    }    }    
}

As I said this class only manages a single set of topics in a single grid and it defined as a managed bean in your page flow definition for the relevant view something like this:

  <managed-bean>    <managed-bean-name>revealManager</managed-bean-name>    <managed-bean-class>oracle.demo.view.RevealPanelManager</managed-bean-class>    <managed-bean-scope>view</managed-bean-scope>    <managed-property>      <property-name>panelCount</property-name>      <property-class>java.lang.Long</property-class>      <value>3</value>    </managed-property>  </managed-bean>
Notice how the expected panel count (3) in this case  is injected into this bean.

Once this management bean is defined then the content that we want to hide and display dynamically (e.g. the triangle panelGrouplayout and the revealPanel panelGrouplayout) and both use expression language to determine if they should be visible. e.g. 

<af:panelGroupLayout layout="vertical"                      styleClass="triangleMarker"                     visible="#{viewScope.revealManager.revealed[0]}"/>
Where the zero based index number is passed into the list evaluation. 

The Click Event Handler

The final thing we need to do is to find a way to call the toggleState() method in the revealManager. The only twist here is that we don't want to have a commandButton or link in the panel to click. We want to be able to click anywhere on the panel.
This is a well established technique so you can look at the demo for the details of the code, but basically we define a small JavaScript function which is registered with the client side click. When the user clicks, this reads the numerical ID of the panel that was selected and makes a call back to the server to the handlePanelToggle() server listener method. That then talks to the revealManager, setting the id of the panel to toggle and invoking the toggle, finishing off with a partialUpdate to get the whole grid to re-draw. Have a look at the RevealRowComponentHandler.java class in the demo for the details.  

And the Result

Well here's the ADF implementation of the revealPanel. First closed:


And now opened:



The Demo

I've uploaded a demo that shows the basic version of revealPanel discussed here and a more advanced version which I'll write a separate article on . You can download the sample from the ADF Code Samples Repository:
Note: The sample is written in 11.1.1.7 it will not work in 11.1.1.6 or older, but it should upgrade to 11.1.2.3+ without a problem 

Viewing all articles
Browse latest Browse all 19780

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>