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).
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.
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.
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.
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.
Dang. I can’t change my post. I noticed a typo (‘to’, instead of ‘two’), but more importantly, I wanted to clarify that the two selectOneChoice/barGraph pairs point to DIFFERENT master/detail sets in the data control.
I’m playing with panelDashboard and your page here has helped answer some questions for me. I have a question that I hope you can help with, even though it’s not exactly to do with panelDashboard.
On my panelDashboard, I have to panelBoxes. Within each panel box, I have a selectOneChoice, associated with the ‘master’ in the data control, and a barGraph, associated with the ‘detail’ in the data control. The problem is that only one of the two select boxes ever works. In other words, if sb2 is the ‘working’ one, then when I select an entry in sb2, the graph for sb2 changes as expected. If I select sb1, the graph for sb1 doesn’t change — until I make a change in sb2. Then both graphs update.
It’s probably something I should already know, but I’m pretty new to this…
Â
Thanks.
Thanks A lot …. Really a great Sample.
percentages will not work. You need to use px. If you do so, you can get the desired result which is two boxes next to eachother with different heights
In one of your posts you’ve said that the panel boxes can be of different sizes and that can only be done using instyle.
What is the recommended approach for displaying 2 panel boxes, layout=vertical, heightPanel1=40%, heightPanel2=80%? Can this be done in a panelDashboard?
Thanks,
Adrian
Hi Christian,
Thanks for the compliments. I have the answers to your questions.
The first answer can be found at the JDeveloper Forum.
The answer to the second question: You can change the label dynamically. To achieve that you hve to bind the component to a bean. In that bean you can access all properties of the component. By invoking <Yourcomponent>.setText(<new label>) you can change the label.
Good luck with that. If you need more help, feel free to get back to me.
Luc
Hello!!
Good tutorial!
I have two questions:
1. How can I add a dragsource component form java code? I’m adding dinamically components in a jspx and I’d like to add d&d function. So I add a panelBox, inside a UIComponent (input box etx..) and now I need the DragSource… 🙂
2. Is it possible to modify dinamiucally a Label of a UIComponent, for example clicking on it?
Thank you very much 🙂
Cristian
Is there a way to use another layout with the paneldashboard ?
I would like to be able to set different sizes for each cell
Andry,
At your first problem: 3 seems to be a “magic number”. Untill now I don’t have a clue on why this doesn’t work.
I have to look into the second problem if you need this fixed.
Luc
Hi Luc,
I have download your application. Very nice and very helpful this example.
I have two problems:
1) When I choose “three columns” I don’t see the page with the dashboard
2) When I modify the order of the panel and I click on “hide”, the page does not hide the correct panel (so that the panel just reordered), but it hides the panel that was in the previous order. So, if I switch the position of the panelBox1 (position 1) with the position panelBox2 (position 2) and then I click on “hide” of the panelBox1 (now in the position 2), the dashboard hides the panelBox2
I am using Jdeveloper 11.1.1.0 and Vista. I read in the blog that the problem would be Vista, doesn’t it?
Andry
Hi Luc,
I’m currently implementing a dashboard, and found your tutorial very helpful. I moved onto a new version, based on the ADF hosted demo dashboard, but I’m having a problem with maximise. I posted on
http://forums.oracle.com/forums/thread.jspa?messageID=3715127
But haven’t had any answers. Perhaps you might have an idea?
Barry
Hi Larry,
a panelbox has the functionallity to be collapsed hence showing only the titlebar. So the answer to your question is yes.
You can dot that by setting the showDisclosure property of the panelbox to true (or not set it at all, because that will result in the default property ‘true’). In the upper left corner there will be an icon visible. When you click it the box will collapse (or expand if allready collapsed)
Hi Lucas,
panelBoxes do not need to have the same height. You could use the inlinestyle property of the panelbox to size the boxes.
This works nice as long as the height is less than the rowHeight property of the dashboard. If it is more, the box will be drawn without it’s lower border. This doesn’t look very nice, but it works.
Jakub, I’ve just uploaded my demo dashboard application.
An extension to Lucas’s question: Is it possible to collapse the panelBoxes (individually) to show only their title bars, as you can in My Yahoo! (or similar portal page), for instance?
Very nice and good Demo!
The example code would be very helpful 😉
kind regards, Martin
Hi Luc
Very nice article! Very complete overview of the functionality of this component. Should help us all to quickly get started with it. By the way, do I understand correctly that all panelBoxes need to have the same height?
best regards, Lucas
Hi Luc,
Could you make accessible to download application you described abowe ?
Kuba