Friday, July 29, 2005

Navigation Wildcards

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.


Most problems in computer science can be solved by adding a level of indirection!



In JSF, navigation is done through an indirection table. Rather than having each button that navigates to another page know its destination, a level of indirection has been added such that the buttons only specify a navigation case name, and then there is a central navigation table which records the actual destination to navigate to for a given navigation case. (A navigation case is simply a short string that describes the navigation intent, like "failure", or "loggedin", or "next" and "previous" in a wizard scenario for example.)



This has some really important advantages. It makes it extremely easy to change the page flow later, since it is not spread out across all the web application pages. The indirection also makes it possible to add a some additional logic to the destination lookup. One such feature offered by JSF is wildcards.



For example, let's say you want to have a Help button. The navigation associated with the help button is "help" - in other words, its action property is set to "help".


<ui:button text="View Help" action="help" binding="#{Page1.button1}" id="button1" />



Navigation Screenshot

We can obviously link this particular button directly to the Help page. That will
result in the following navigation rule being added to the navigation rule file:



<navigation-rule>
<from-view-id>/Page1.jsp</from-view-id>
<navigation-case>
<from-outcome>help</from-outcome>
<to-view-id>/HelpPage.jsp</to-view-id>
</navigation-case>
</navigation-rule>


But what if we had a help button on every page? Would we have to repeat this

rule for each and every from-page?



No. This is where wildcards come in. You don't have to specify the
source page in the above rule; you can use "*" instead which means "any" page:



<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>help</from-outcome>
<to-view-id>/HelpPage.jsp</to-view-id>
</navigation-case>
</navigation-rule>


Now, ANY page specifying a navigation case of "help" will result
in navigaton to the given Help page.



Wilcards play a very important role with page fragments. A page fragment
is essentially a "static" include of a portion of a page: it literally gets
copied into the referencing page at deployment time. Thus, if you have a Page fragment (such
as a Footer page fragment listing copyrights as well as a Contact Info
button), every single page including this page fragment will have the
Contact Info button. If you bring up the page navigation editor and zoom
a page, you'll see buttons and links from fragments that are included in the
page too. However, note that there is only a single JSP for the fragment
with the button, even if it's included in multiple pages. Thus, its action
property can only be set to one thing. If you drag this button to a destination
page, this both adds a navigation rule from this Page and sets the
action property of the fragment. This action property will now be seen in
all other pages including the fragment too. You cannot set the action property
to different values for different including pages. (You can however
have different navigation rules for the same action when used in different pages,
as discussed shortly.)



Because of this, you usually want to use wildcards when you're using navigation
components (like buttons and links) in fragments. This will ensure that
regardless of which page the fragment button is clicked from, the same
target page is chosen. This will for example ensure that your "Contact Info"
button will bring up your page with Address, Phone, and E-mail information regardless
of which page the user clicked the fragment button from.



Note however that you don't have to use wildcards with fragments - using
normal navigation rules also gives you some really powerful possibilities. For example,
if we go back to the Help example, your Footer fragment could have a Help button,
but you can bind it to -different- destination pages for each different source page.
Thus, you can have context sensitive help!



Unfortunately, the navigation editor doesn't help you with wildcard rules. You'll
have to add these by switching to the XML view. Also, wildcard rules are shown as
erroneous rules - the arrow flows into the destination
pages and show the case names, but the page flows from an error icon. It should
flow from a wildcard icon instead.



P.S. If you're wondering why there's a blue border around the left page
in the screenshot, that's because my coworker
Winston implemented
full keybord support for the navigation editor recently, and the blue border signifies that
the page is current. Tabbing switches pages, z/u zooms and zooms a page, b adds a
button, s selects start page, tab to switch, then e ends and creates link, Ctrl-A adds a new page, etc.


No comments:

Post a Comment