Showing posts with label wicket. Show all posts
Showing posts with label wicket. Show all posts

Monday, September 10, 2012

Wicket Multiple Choice Select Box

The component to use for this is the ListMultipleChoice class.

Tuesday, July 10, 2012

Apache Wicket: AjaxSubmitLink No Response

What happens is when you click the AjaxSubmitLink, there is no response, no error messages, and you don't know why there is a problem.

This is potentially a gotcha caused by "setRequired(true)" in your form elements. The form will refuse to act (and won't tell you why) when you leave a required field blank.

Friday, June 1, 2012

Wicket Feedback Panel

Convenient way of adding feedback messages.

In each component, just call info(), debug(), warn(), error() to send messages to the FeedbackPanel

Wicket Request Cycle Customization

There are times where you'd need to add some custom logic in the Request Cycle itself. One example is when your site has single-sign-on integration with other sites. What that means is that you'd have to check the validity of the session from time to time.

Putting this checking logic in the Page class (or a general super-class Page) is not the answer, as you'd need to also perform these checks for Ajax requests that don't load a new page. The best way to do it is to add this logic into the Request Cycle.

In Wicket 1.5, the Request Cycle API as changed. To add some logic to the Request Cycle, create a concrete implementation of AbstractRequestCycleListener, and then add it from the Application object.

protected void init() {
    getRequestCycleListeners().add(new YourCustomizedRequestCycleListener());
}

In YourCustomizedRequestCycleListener, override 2 methods:
  • onRequestHandlerResolved:
    • The request cycle listener callbacks are called for all kinds of requests, including requests for CSS files and Images, by putting the session logic here, you'll be able to differentiate between Page / Ajax requests and other requests)
    • Page requests: Test handler to be of class RenderPageRequestHandler
    • Additionally, you may even need to check to exclude certain pages (e.g. public pages, error pages). Get the page class using this: ((RenderPageRequestHandler)handler).getPageProvider().getPageClass())
    • Ajax requests: Test handler to be of class ListenerInterfaceRequestHandler (which may also include non-Ajax requests but we want to include them too)
  • onException (if you need to send users to an error page, throw an exception inside onRequestHandlerResolved and handle it here)
    • To send user to error page: return new RenderPageRequestHandler(new PageProvider(ErrorPage.class));
Notes: This seems to be quite a lot of work to do something that's actually a pretty common requirement. Maybe there can be an easier way to do it. In any case, this works.

Data Table Component in Wicket

Wicket provides a Data Table component that can be easily reused to create data tables.
  • Use the class AjaxFallbackDefaultDataTable
  • Define the columns by creating them one-by-one and adding them to the Data Table
  • This can be an AbstractColumn where you provide the component to use inside the cell
  • Or a PropertyColumn where the cell shows data bound to a model
  • Also provide a database provider implementing SortableDataProvider
  • Within the provider, implement iterator, size, and model methods
  • The table can be styled via CSS that you provide
Example code can be found in Wicket Examples

References:

Making Wicket Log to Log4J

Just add file slf4j-log4j12-1.6.4.jar (other versions will probably work too) to the classpath of the web-app.

Download file from: http://www.slf4j.org/download.html

Table Cell Background Image in Wicket

HTML code for TD background image:
<td style="background-image: url(abc.png); background-repeat: no-repeat;">

Wicket code for generating this code:

First step is to obtain the URL of the background image. Let's say this time the image is in the package (i.e. together with the Java & HTML classes for a more object-oriented approach).

PackageResourceReference bgImageResource = new PackageResourceReference(this.getClass(),"abc.png");
String imageUrl = RequestCycle.get().urlFor(bgImageResource, new PageParameters()).toString();

imageUrl is the relative path from the context root to the image file. However, this URL will not work as-is, as the current page is unlikely to be on the context root.

To generate full URL:

imageUrl = RequestCycle.get().getRequest().getContextPath() + "/" +imageUrl;
getContextPath is new in Wicket 1.5.

Lastly, create the style attribute with an AttributeModifier.

tdElement.add(new AttributeModifier("style", "background-image:url("+imageUrl+");background-repeat: no-repeat;"));

Wicket: Running Javascript On Client-Side Before Submitting Data to Server

In Wicket, we usually depend on the server-side logic to perform AJAX updates on the page. However, that's not always practical. It could be because of performance reasons, or in the case of file uploads, a limitation of the Wicket framework. For the latter, it's because no AJAX updates via Wicket is possible until the file upload is completed. If for example I wish to hide the upload button immediately on submission, that can't be done via Wicket's AJAX.

To achieve this, we can use an AttributeModifier to prepend Javascript to e.g. the "onchange" attribute of the file upload input element.
fileUploadField.add(new AjaxFormSubmitBehavior(this,"onchange") {
// ----- implementation snipped ----------
});
fileUploadField.add(AttributeModifier.prepend("onchange", "this.style.visibility='hidden';"));

Java Generics: Void

Use Void when the class type in the generics is not relevant for the situation.

For example, in Wicket's AjaxLink, it doesn't always have a model. In that case we can use AjaxLink<Void>.

Brix CMS for Wicket

The main problem with almost all the CMS out there is that they are optimized for building websites. They are not optimized for building web-apps. In fact, for some of the most popular ones (e.g. Drupal, Joomla), they require software engineers to commit to huge compromises when they want to build a web-app. Why should software engineers have to compromise just because they need CMS functionality? That's a question I've always been asking.

My favorite web application development framework is Apache Wicket, which allows web applications to be built in a truly object oriented manner, and all I need for some of my projects is to be able to build a web-application with some CMS capabilities without having to go slumming with PHP or do some crazy hacks to integrate a CMS with the web-app. I'm just so sick of all the "our way or the highway" (The "Drupal Way" *rolleyes*) approach to developing web-app functionality into CMSes.

Brix CMS claims which I like and find promising:
  1. "Most CMS are for building web sites. Brix CMS is for building web applications."
  2. "BRIX is not a standalone CMS, but rather a CMS framework which allows for easy integration of CMS functionality into existing Wicket-based applications."
Obviously these claims will have to be examined, something which I will be doing soon:

Links:
  1. http://blog.dreamcss.com/content-management-system/brix-apache-wicket-based-cms-framework/
  2. https://github.com/brix-cms/brix-cms
  3. https://github.com/brix-cms/brix-cms/wiki

Removing the "Choose One" Option From Wicket's DropDownChoice

It's a bit of a hack how to do this. Basically it involves triggering some convention by:
  • Extend the DropDownChoice class
  • Add the following code to override a method:
@Override
protected CharSequence getDefaultChoice(Object arg0) {
return "";
}

Wicket Modal Window Form Issue

Wicket has a strange problem with forms that requires a work-around. It says in the Javadoc of ModalWindow:

"If you want to use form in modal window component make sure that you put the modal window itself in another form (nesting forms is legal in Wicket)"

If this is not done, when using Firefox, form submissions may not be successful.

It appears that this issue exists due to backward compatibility constraints with IE6.

In order to work around this, it is required to put the modal window in another form, like this:

<form wicket:id="modalWindowForm">
<div wicket:id="modalWindow"></div>
</form>

References:
  1. wicket.apache.org/apidocs/1.4/org/apache/wicket/extensions/ajax/markup/html/modal/ModalWindow.html
  2. issues.apache.org/jira/browse/WICKET-3146
  3. issues.apache.org/jira/browse/WICKET-3404
  4. www.techienuggets.com/Comments
  5. apache-wicket.1842946.n4.nabble.com/Form-tag-does-not-get-rendered-on-a-Panel-placed-in-a-TabbedPanel-within-a-ModalWindow-td1887897.html
  6. issues.apache.org/jira/browse/WICKET-2214
  7. web.archiveorange.com/archive/v/yH01cYmiI4SdLFnAfqjy

Building a Wicket Component Which Updates Itself When the Model Changes

For a component to update itself when model is updated:
  • Implement a method (e.g. update) that updates the UI components. This can be called from:
    • the constructor and
    • whenever the model is changed.
  • Override the onModelChanged method, like this:
@Override
protected void onModelChanged() {
super.onModelChanged();
update();
}
  • onModelChanged will be automatically called by Wicket IF the reference of the Model Object has changed. Deep changes (e.g. changes in one of its fields) will not be detected.
  • So in order for onModelChanged be called, either:
    • replace the Model Object with a modified clone (in which case Wicket will automatically call it) OR
    • call onModelChanging & onModelChanged manually.
  • Ensure that the Component is added to an AjaxRequestTarget and it will be updated via AJAX automatically

Wicket Handling JavaScript Events

Wicket provides useful classes for handling of JavaScript events such as:
  1. onMouseOver
  2. onMouseOut
  3. onFocus
  4. onBlur
  5. onKeyUp
  6. onKeyDown
  7. etc.
Full list of events here www.w3schools.com/jsref/dom_obj_event.asp
To handle a JavaScript event e.g. onMouseOver on an element on the page hierarchy, add the following:

add(new AjaxEventBehavior("onMouseOver") {
    protected void onEvent(AjaxRequestTarget target) {
        // do something.....
    }
}
);

AjaxFormSubmitBehavior can be used in a similar way to achieve the same results when it is necessary to capture information for processing (e.g. real time search)

Also note that for very chatty Ajax events like onKeyUp & onKeyDown, setThrottleDelay can be used.

Working with CSS & JS Files in Wicket

In Wicket, the preferred choice of serving CSS/JS files is as a resource from the JAR instead of from a physical file inside the web folder. The API provides an easy way to get it done that also comes with a lot of flexibility & modularity.

Basically you can call from anywhere in your Java code:
  • add(CSSPackageResource.getHeaderContribution(NiceButton.class, "button.css"));
And in the case of JavaScript:
  • add(JavascriptPackageResource.getHeaderContribution(SomePanel.class, "panel.js"));
And the links to the CSS & JS file will automatically be added to the header of the page.

This also means that at the Page class level, you can choose to either use the CSS file provided by the component, or override and add your own instead.

Also, there is an option to provide a location instead (the more traditional way for web-apps) with the "getHeaderContribution" method.

Reference: Wicket WIKI

Wicket Replace Page Title with AJAX

In Wicket, trying to make the page title a Label backed by a property model & trying to change the title by changing the underlying property during an AJAX request by will result in a JavaScript bug in IE.

The way to change the title dynamically via AJAX that works across browsers is to append JavaScript to the AJAXRequestTarget e.g.:
target.appendJavascript("document.title='"+newTitle+"'");

Wicket Images Without Using Resource Streams

Wicket's Image object is based on resource streams which is different from more traditional ways of handling images. For more "traditional" ways of handling images, the following options are available:
  1. Construct an Image object without any resource streams i.e. new Image(id) and add a AttributeModifier to change the src attribute.
  2. Use a ContextImage (link).
  3. Create own Image class and add the attribute changing logic in the "onComponentTag" callback (link).

Wicket i18n

Wicket's default i18n implementation is component based. It will look for a properties file matching the component and then outward from there.

References:
  1. cwiki.apache.org/WICKET/i18n-and-resource-bundles.html
  2. day-to-day-stuff.blogspot.com/2008/05/wicket-internationalization.html
  3. www.informit.com/guides/content.aspx
However, to customize the i18n data source, add a line in Application implementation's init():

getResourceSettings().addStringResourceLoader(new CustomStringResourceLoader()); 

where CustomStringResourceLoader is a concrete custom implementation of IStringResourceLoader.

Reference:
  1. apache-wicket.1842946.n4.nabble.com/Howto-load-StringResources-from-Database-for-Iternationalization-td1893587.html

Wicket: Access Servlet Session & Page Redirection

Access Servlet Session

This is sometimes necessary when Wicket pages need to co-exist with servlet based ones.

((WebRequest)getRequest()).getHttpServletRequest().getSession(); 

Page Redirection
getRequestCycle().setRequestTarget(new RedirectRequestTarget("home.jsp"));

Wicket on Google App Engine

According to this blog post, it can be done pretty easily.

Of course the persistence limitation (i.e. no filesystem, have to use Google's DB) still stand.