ADF 11g PanelDashboard; configure your own dashboard

With the recent ADF release a new component is introduced: The panelDashboard component. A component that is easy to use and offers a very visual presentation. With this component we can quickly create a dashboard that consists of panelBox components that can each provide their own content. The dashboard lays these panelBoxes out in a grid – we can specify the number of columns in the grid. With a minimum of configuration (just by adding dropSource components) we can make the panelBoxes drag-and-droppable, allowing the user to reconfigure the dashboard. These re-configurations can be persisted at session level or (using MDS) across sessions. In this post I will explain some of the features of this panelDashboard component, and I will show some usages.

PanelDashboard is not a component you will use all over the place, but one that will certainly be useful for the home page/portal like dashboard that exist in many applications.

Here are some steps you can take to use the PanelDashboard.

1. Create a panelDashboard.

Add PanelDashboard to your page (usually you will use a page template that exposes facets for header, sidebar and footer as well as content or body; the panelDashboard will go into the content or body facet).

ADF 11g PanelDashboard; configure your own dashboard createpaneldashboard

Set the number of columns in the dashboard (2 or 3 are the most obvious values), or bind it to a bean property so the end user can change the number of columns and the rowheight runtime.

<af:panelDashboard id="dashboard"
                                      columns="#{dashBoardConfigurator.numberColumns}"
                                      partialTriggers="sor1 sor2"
                                      rowHeight="#{dashBoardConfigurator.myRowHeight}"
                                      binding="#{dashBoardConfigurator.myDashboard}">
</af:panelDashboard>

If you create a group of radiobuttons to set the values of columns and rowheight (something you would typically put in a side bar), the user can create his own layout.

2. Add panelboxes and content.

Next thing to do is adding PanelBox components to the dashboard; four seems to be the minimum for a meaningful dashboard. Set titles for the panelBoxes and add content where available.

<af:panelBox id="panelBox6" text="panelBox 6" rendered="true">
   <af:outputText value="panelBox 6 content" id="ot6"/>
</af:panelBox>

With the panelboxes in place you now have a functional dashboard in which you can change the number of columns that your dashboard displays. If all of the child panelBoxes cannot fit within the dimensions of the panelDashboard (e.g. due to the specified number of columns and row height), then the panelDashboard will provide a scroll bar so that the user can access the panelBox children that might not be initially viewable.

ADF 11g PanelDashboard; configure your own dashboard dynamiccolumns


 

 

3. Implement drag and drop.

If you want the dashboard to be configurable, you should add componentDragSource child components to the panelBoxes. This will allow them to be draggable-droppable. The panelDashboard component handles the drop event and the subsequent rearrangement of the panelBox components.

<af:panelBox id="panelBox6" text="panelBox 6" rendered="true">
   <af:outputText value="panelBox 6 content" id="ot6"/>
   <af:componentDragSource/>
</af:panelBox>

This is actually all you need to create a dashboard with drag and drop functionallity to move the dashboard items around.

ADF 11g PanelDashboard; configure your own dashboard dnd
 

4. Advanced features.

One of the somewhat more advanced configuration options would be the implementation of show and hide functionallity. The panelDashboard component provides an API that you can access to allow users to switch child components from being rendered or not rendered, giving the appearance of panelBoxes being inserted or deleted. If you want to add and remove dashboard items in a user friendly way, you could add a panelDashboardBehavior child component to the command components that you use to add and remove items. It is important to note that you are not required to use a behavior tag to do this. The benefit of using this behavior tag is that it will immediately start opening up space for the content before the server starts processing the action event and the managed bean makes the changes to send down the new panelBox content. If you decided not to use a behavior tag, the user may experience a delay while the server code is processing; the space within the dashboard will not open up until the new content is retrieved from the server.

In the panelboxes you need a commandlink which you would place inside the toolbar facet. To allow insertion and deletion of components, implement a listener on the commandlinks (actually command component) to handle the action. Bind the actionListener for the command component to a handler on a managed bean that will handle the changes to the component tree. Also put an attribute element within the commandlink. This attribute should contain the value of the panelbox’s id. Within the listener you need this to be able to determine what panelbox should be deleted.

<af:panelBox id="panelBox6" text="panelBox 6" rendered="true">
   <af:outputText value="panelBox 6 content" id="ot6"/>
   <af:componentDragSource/>
      <f:facet name="toolbar">
         <af:commandLink partialSubmit="true" text="hide"
                                           actionListener="#{dashBoardConfigurator.handleDelete}"
                                          id="cil6">
               <f:attribute name="panelBoxId" value="panelBox6"/>
         </af:commandLink>
        </f:facet>
</af:panelBox>

In the handler code call the panelDashboard component’s prepareOptimizedEncodingOfDeletedChild() method, which causes the dashboard to re-render only the part that actually changes, being the one box that was deleted (when inserting you would use prepareOptimizedEncodingOfInsertedChild).

The handle delete code in the backing bean takes care of the actual deletion.

     public void handleDelete(ActionEvent e)
    {
      // get the component that triggers the event  
      UIComponent eventComponent = e.getComponent();
      // Set the panelboxId by getting the value of the components panelBoxId attribute
      String panelBoxId = eventComponent.getAttributes().get("panelBoxId").toString();
      // Find the actual panelbox in the dashboard
      UIComponent panelBox = _myDashboard.findComponent(panelBoxId);
      // Make this panelBox non-rendered:
      panelBox.setRendered(false);
      // The dashboard is already shown so only perform an optimized render so the whole
      // dashboard doesn't have to be re-encoded:
      int deleteIndex = 0;
      // get all children of the dahsboard
      List<UIComponent> children = _myDashboard.getChildren();
      for (UIComponent child : children)
      {
        if (child.equals(panelBox))
        {
        // As soon as we find the box that we deleted, do the deletion and quit the loop
          _myDashboard.prepareOptimizedEncodingOfDeletedChild(
            FacesContext.getCurrentInstance(),
            deleteIndex);
          break;
        }

        if (child.isRendered())
        {
          // Only count rendered children since that's all that the panelDashboard can see:
          deleteIndex++;
        }
      }     
    }

When you now click the “hide” link in one of the panelboxes, the dashboard is partially re-rendered and the box is actually removed from the dashboard.

ADF 11g PanelDashboard; configure your own dashboard beforehide

Pretty nice component this panelDashboard.

Last year I had to build a dashboard in ADF10.1.3.4 for one of my customers. I succeeded, however, there’s no need to tell you how difficult that was. I can’t tell you how happy I am with this new component.

5. Download available.

You can download the demoDashBoard here. All you need is a connection to the HR schema.

18 Comments

  1. Jeff R February 22, 2012
  2. Jeff R February 22, 2012
  3. Mangal Dev October 30, 2011
  4. Luc Bors October 25, 2011
  5. Adrian October 14, 2011
  6. Luc Bors February 9, 2010
  7. Cristian February 5, 2010
  8. JP October 19, 2009
  9. Luc Bors September 29, 2009
  10. Andry September 24, 2009
  11. Barry August 26, 2009
  12. Luc Bors July 20, 2009
  13. Luc Bors July 13, 2009
  14. Luc Bors July 13, 2009
  15. Larry July 11, 2009
  16. Martin July 10, 2009
  17. Lucas Jellema July 10, 2009
  18. Jakub Pawlowski July 9, 2009