7/16/07 Update: Thanks to Antonio, this blog entry is now available in Spanish.
Page fragments enable you to add a particular set of components, action handlers,
and functions to a bunch of web pages. When you add a Page Fragment Box to a
page, you are first given the option of choosing an existing page fragment or
creating a new one, and then the IDE adds a <jsp:directive.include>
tag to the main page (the page that includes the fragment). When you create
a page fragment, the IDE adds both a .jspf file and a backing bean
to the project.
The <jsp:directive.include> directive is not the same as,
the <jsp:include> standard action. The directive causes the
contents of the page fragment to be placed into the main page’s .jsp
before the .jsp file is translated into a servlet.
The page fragment’s backing bean extends AbstractFragmentBean,
which, unfortunately, does not provide the preprocess or prerender
methods. It only provides the init and destroy methods.
When a person lands on the page from another destination, such as by typing
in the URL or clicking a link, the server instantiates the fragment’s backing
bean (and thus calls the init method) the first time that fragment
is referenced. In general, this is likely to happen during the render response
phase. On a postback (that is, when the page redisplays itself in response to
a page submission) , the fact that the saved component state includes component
bindings to properties in the fragment’s backing bean will cause the server
to instantiate the page fragment’s backing bean much earlier.
Because the page fragment’s init method can be called early in
the lifecycle,
you cannot reference or set component values in the init method.
Conversely, a page fragment’s init method might not be called until
during or after the main page’s prerender call. A workaround for
this is to put methods in your page fragements and call those methods from the
main page’s prerender. For example, you can add a prerenderFragment
method in each of your page fragments. Then for each fragment that you include
in the main page, add code like the following:
public void prerender() {
TopFragment topFragment = (TopFragment)getBean("TopFragment");
topFragment.fragmentPrerender();
...
}
|
Here are some code snippets to illustrate some common page fragment tasks:
Passing Data Between the Main Page and the Page Fragment
You can pass data to a page fragment through the a managed bean (request bean, session bean,
application bean), or through function arguments as shown below
In the following snippit, the main page passes information to the page fragment
by argument:
public void prerender() {
Bike bike = getSessionBean1().getBike();
...
PriceTable priceTable = (PriceTable) getBean("PriceTableFragment");
totalsSubtotalPrice.setText(priceTable.subtotal(bike));
}
|
Here, the main page sets the values in the request bean, which the page fragment
then picks up and uses. This is from a web application where the user selects
an item from a drop-down list in the main page, which, in turn, refreshes the
trip data provider in the page fragment.
// Page Fragment
public void fragmentPrerender() {
if (getRequestBean1().getPersonId() != null) {
try {
getSessionBean1().getTripRowSet().setObject(
1, getRequestBean1().getPersonId());
tripDataProvider.refresh();
} catch (Exception e) {
error("Cannot switch to person " +
getRequestBean1().getPersonId().toString());
log("Cannot switch to person " +
getRequestBean1().getPersonId().toString(), e);
}
}
}
|
// Main Page
public void prerender() {
// If not a postback, set the default person
if (getRequestBean1().getPersonId() == null) {
try {
personDataProvider.cursorFirst();
getRequestBean1().setPersonId(
(Integer)personDataProvider.getValue("PERSON.PERSONID"));
} catch (Exception e) {
error("Cannot switch to person " +
personDataProvider.getValue("PERSON.PERSONID"));
log("Cannot switch to person " +
personDataProvider.getValue("PERSON.PERSONID"), e);
}
}
Fragment1 fragment1 = (Fragment1) getBean("Fragment1");
fragment1.fragmentPrerender();
}
|
Changing Component Properties in a Page Fragment
The main page can access and modify components in the page fragment through
the page fragment’s bean object, as shown below:
public void prerender() {
Navigation navigationFragmentBean = (
Navigation)getBean("Navigation");
Hyperlink homeLink = navigationFragmentBean.getHomeLink();
homeLink.setDisabled(true);
}
|
Determining What Page the Page Fragment is Included In
In this code snippet, the page fragment changes its apperance based
on what page it is being displayed in.
public void fragmentPrerender() {
// If they are done, show the checkout button
String page;
String viewId = getFacesContext().getViewRoot().getViewId();
if (viewId == null || viewId.length() == 0 || "/".equals(viewId)) {
page = "";
} else {
int pos = viewId.lastIndexOf('/');
if (pos == viewId.length() - 1) {
// last char in viewId is '/'
viewId = viewId.substring(0, pos);
pos = viewId.lastIndexOf('/');
}
//ok if pos is -1, then pos+1 will be 0
page = viewId.substring(pos+1);
}
checkoutButton.setRendered(FINAL_ORDER_PAGE.equals(page));
}
|
Using a Tab Set in a Page Fragment for Navigation
Yossarian, a Creator/NetBeans IDE user, submitted this tutorial to the Creator
Community Docs Site: Simple
Page Fragment Menu Example.
Dynamically Rendering a Page Fragment Component From the Main Page
Here is a snippit where the main page dynamically renders a tree in a page fragment
public void makeTree() {
Fragment2 pgfrag = (Fragment2)getBean("Fragment2");
List children = pgfrag.getDisplayTree().getChildren();
TreeNode personNode = new TreeNode();
personNode.setId("node1");
personNode.setText("Shari Oln");
children.add(personNode);
}
|
Other Examples
In Winston’s blog
he points to Josh’s web site, which uses VWP page fragments to do wonderous
things. How about you? Do you have some super page fragment tips to share? If
so, post them to the comments below to share with other VWP developers.