(Also published in
Dutch and
French, French translation by
ZedroS).
Despite the general acceptance of AJAX, there is still some reticence in some sectors. The rich interaction provided by AJAX can not be used by people that, because of their handicap have to use a browser that does not support Javascript or CSS. For a sector like the government it is not acceptable to exclude these people and I believe this is an attitude that should be practiced more often.
Many developers today can or will only create web applications that work solely in Internet Explorer. Building an AJAX application that also works without Javascript is simply too much for many companies. To do this anyway, a number of techniques are known. A more general approach is given by Unobtrusive Javascript, but this article presents a different, more flexible approach that uses Wicket.
Wicket is one of the few fully component based web frameworks. In such a web framework one combines components to larger components until you have a web page. The advantage of components is that it is a lot more comfortable to develop and modify components separately. With a page oriented web framework one must usually develop the whole page simultaneously. Struts for example prescribes that you first collect all information for the whole page before a JSP page will render the (whole) page.
Composing Wicket components (a Wicket introduction)
Once creates a component in Wicket by writing an HTML fragment (the template) and by writing Java code that couples more components to the template. Creation and coupling of components happens during the construction phase. During the render phase the components can add or change the fragment or even completely replace it.
Lets look at an example. Here is an HTML template and the associated Java code:
<h1 wicket:id="title">_Template title</h1>
add(new Label("title", "The real title"));
The Label component is coupled to an
h1
element. Label will put the real title in the HTML template during the render phase. The result is:
<h1>The real title</h1>
Composing components is just as simple. Suppose we want to use a title with subtitle on many places. We will create a component for that, a Panel to be precise:
<wicket:panel>
<h1 wicket:id="title">_Template title</h1>
<h2 wicket:id="subtitle">_Template subtitle</h2>
</wicket:panel>
class TitlePanel extends Panel {
public TitlePanel(String id, String title, String subtitle) {
super(id);
add(new Label("title", title));
add(new Label("subtitle", subtitle));
}
}
The panel can now be used (for example in the template of another panel) with:
<span wicket:id="titlepanel"></span>
add(new TitlePanel(
"titlepanel", "The real title", "with a subtitle"));
Linking between pages is done with the Link component:
<a href="#" wicket:id="detaillink">Book details</a>
add(new Link("detaillink") {
void onClick() {
setResponsePage(new DetailPage(bookId));
}
});
The Link component will put a Wicket generated
href
attribute on the
a
element during the render phase. When the link is clicked the Wicket servlet will call the
onClick
method. In this example the response page is changed to a page that is constructed on the spot (pages are of course also components). After this the response page is rendered and sent to the browser. If the
onClick
method was left empty, the response page would not have changed and the current page is rendered again.
Dynamic pages in Wicket
Links are not only for jumping to other pages. In Wicket it is just as easy to change a part of the page by replacing a component by another one. Lets extend the example a bit:
final BookDetailPanel bookDetailPanel = ...;
add(bookDetailPanel);
add(new Link("detaillink") {
void onClick() {
bookDetailPanel.replaceWith(
new BookDetailPanel(bookId));
}
});
Clicking the link leads to a change in the current page. After this the current page is rendered again, and another book is displayed. Note that exceptionally little code is needed. In many other web frameworks all information of the complete page must be collected again.
The observant reader will have noticed that replacing a piece of a page is a trick that is nowadays mostly done with AJAX. In the example however, we have not used a single line of Javascript. Since the whole page is send to the browser again and again, lets change the example a bit more:
final Component bookDetailPanel = ...;
bookDetailPanel.setOutputMarkupId(true);
add(bookDetailPanel);
add(new AjaxFallbackLink("detaillink") {
void onClick(AjaxRequestTarget target) {
Component newBookDetailPanel =
new BookDetailPanel(bookId);
newBookDetailPanel.setOutputMarkupId(true);
bookDetailPanel.replaceWith(newBookDetailPanel);
if (target != null) {
target.addComponent(newBookDetailPanel);
}
}
});
During the render phase the component AjaxFallbackLink generates both a
href
and an
onclick
attribute on the coupled
a
element. Furthermore it makes sure that a number of Wicket Javascript files are added to the HTML header.
Depending on whether Javascript is supported, the browser will request either a normal URL, or it will do an AJAX call. In both cases the Wicket servlet will call the
onClick
method. In the first case the argument of
onClick
is
null
and everything will work exactly as in the previous example. When an AJAX call is done, Wicket will only render the components that were added to the AjaxRequestTarget and the result of that is sent to the browser. On the browser side, the Wicket Javascript searches for the element that needs to be replaced by using the
id
attribute. To make sure it is set, method
setOutputMarkupId(true)
is called.
With just a few lines of code we have created an AJAX application that even works in browsers without Javascript.
Conclusion
This article shows only a small piece of Wicket's AJAX capabilities. For example it is fairly easy to let the user know an AJAX call is in progress, to quickly execute some Javascript before an AJAX call (for example to disable a submit button), or to validate a form input when it changed.
Wicket is not only a fantastic framework to easily build modern and maintainable web applications, it is even possible to do it in such a way that older and special browsers can deal with them.