Monday, April 4, 2005

Tabs, Revisited

WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.


I wrote a

blog entry

a couple of days ago on how to build a
tabbed window setup using only standard JSF components.



The solution used one page per tab. That's okay for a web application
where you really want to have separate contents on each and every page.
But what if you want to have multiple tab sections on each page? Or what
if the tab area represents only a small portion of the page - you would
have to put all the shared contents in a page fragment.



Here's an alternative solution. I'm just going to outline it, since
I think that will be sufficient - but if anyone has trouble, feel free
to ask follow-up questions - you can post anonymous comments if you
are embarassed :-)



Like before, you'll create a set of tabs by putting Link Action components
inside a horizontal grid panel. However, this time, instead of putting
the separate tab contents on separate pages, you will place all of the
tabs in this page, all on top of each other! Then, all of these components
will be "turned off", except for the one which corresponds to the current
tab! We can turn off components by using the "rendered" property on the
JSF components.



So let's begin. As before, create a grid panel, decide how many tabs you
want, drop a link action for each, and set the embedded Output Text values to
the tab names.



For the links however, instead of using navigation, double click on each
link to create action handlers. In the action handler for the third link
for example, write something like this:


currentTab = 3;


You also need to add an integer variable named currentTab to your
page bean:

private int currentTab;



Next you need to go and add the tab contents. Drop a Grid Panel right
under the tab-link-panel Then go and look for its "Rendered" property
(it's probably under Advanced)
and uncheck it. The component should now disappear.
Repeat this process such that you have created as many grid panels
as you have tab links. Now go and re-enable the Rendered property on
one of them. Then drop components inside this grid panel as appropriate
to populate your tab contents.



Note that you won't be able to use "absolute positioning" (where you
can drag & drop components anywhere) inside these tabs. If you want to
do that, create page fragments for these, and then put the page fragment
box inside a panel group component in the grid.



The final thing we need to do is hook up the Rendered properties such
that they get enabled exactly when the corresponding link is selected.
To do that, make our currentTab variable into a property
by adding this method to your page bean:


public int getCurrentTab() {
return currentTab;
}

Now you can change the "Rendered" property for the grid panel number 3
(corresponding to tab link number 3) from "off" to this value binding
expression:

#{Page1.currentTab==3}

You do this by right clicking on the grid panel in the Application Outline,
choose Property Bindings..., select the Advanced radio button,
and then paste the above into the "New binding expression" textfield on
the bottom.

Yes - notice the flexibility in the expression language - we can do
comparisons (in addition to a number of other operations. To learn more
about this, open up the Help dialog in Creator, switch to the Search
box and search for "Expression Language".)



You would obviously adjust this if your page name is something other than
"Page1", and of course the "3" should be adjusted for each link.



Finally, you need to highlight the tab names and use CSS to make the
cells look like tabs. This is precisely like the
last time, so I won't cover it here. You only have
to modify the code which goes and figures out which tab is current.
Last time I had to search to the view root and compare tab names.
That is not necessary now - we know the tab index directly since we
set it in the links!



That's all there is to it - it should work. Note that the designtime
experience here is harder, because once you've value bound the Rendered
properties for each tab section, they don't show up at designtime.
You can temporarily set them back to true, edit, then enable value
binding again. Or, if you use page fragments you can edit the layout
by opening the fragments file.



Good luck!



P.S. In the above I referred to the "third" link and showed an integer of "3",
for simplicity. Remember that the tab index code is 0-based, so you would really set
currentTab=2, compare with ==2 in the value binding expressions, etc.


2 comments:

  1. Tor,
    Can you (or a netbeans developers) please write a small tutorial that demonstrates how to use subversion in netbeans.
    Thanks

    ReplyDelete
  2. Sorry, I don't use subversion, but perhaps
    this
    pointer helps?

    ReplyDelete