<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>
<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:
public TitlePanel(String id, String title, String subtitle) {
super(id);
add(new Label("title", title));
add(new Label("subtitle", subtitle));
} }
<span wicket:id="titlepanel"></span>
add(new TitlePanel(
"titlepanel", "The real title", "with a subtitle"));
Linking between pages is done with the Link component:
"titlepanel", "The real title", "with a subtitle"));
<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 void onClick() {
setResponsePage(new DetailPage(bookId));
} });
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:
add(bookDetailPanel);
add(new Link("detaillink") {
void onClick() {
bookDetailPanel.replaceWith(
new BookDetailPanel(bookId));
} });
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 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);
}
}
});
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.
Thanks for a very well written article. Will be a great eye-opener for wicket-curious people - I will send some to read it immediately. :-)
ReplyDeleteThanks Per for dropping a note. Writing a blog is so unpersonal, you never know whether your work is appreciated.
ReplyDeleteThanks for this brief but conclusive and practical article. I think it should be included in the wicket documentation.
ReplyDeleteI am trying to find if wicket is right for a new project, and had found it to be just what I needed.
Mario
Good article, just what I needed. I am just beginning to dig into Wicket and this helped me.
ReplyDeletegreat article. i wondered how wicket and ajax play together and your example was a great help
ReplyDeleteI always thought that AJAX was a feature of the web browser. Wicket is injecting JS for AJAX calls, so how could it bypass disabled JS???
ReplyDelete@anonymous, it easy to bypass Javascript: just do it on the server!
ReplyDelete