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

Thursday, February 7, 2013

Solution for jQuery plugin conflicts in Wicket

While I was working on a web application based on Wicket, I noticed that jQuery was not functioning in a way I expected. Using FireBug I noticed that a method call to a jQuery plugin failed, because it couldn't find the method. The HTML code I used in the <head>-element looks like this:

  <script type="text/javascript" src="js/jquery-1.7.1.min.js"></script>
  <script type="text/javascript" src="js/jquery-plugin.js"></script>
  <script type="text/javascript">

    function callbackToPlugin() {
      return function () {
        $('#plugin').callToPlugin();
      };
    }

  </script>

The code-fragment includes the jQuery file and the custom plugin file. A function is defined below that returns a callback function that calls the plugin. The code in a Wicket web page class, decides if this callback is used or not. In the code below, the call is rendered in the <head>-element, when the boolean variable "callPlugin" is true.

  @Override
  public void renderHead(IHeaderResponse response) {
    if (callPlugin) {
      response.render(
        OnDomReadyHeaderItem.forScript("$(document).ready(callbackToPlugin())"));
    }
  }

The problem with this code is that Wicket includes its embedded jQuery file in the HTML output automatically, when it detects certain JavaScript function provided by Wicket is used. In this case it includes the jQuery file AFTER the definition of the callback function. What happens is that the definition of the plugin method "callToPlugin" is lost, because the second inclusion of jQuery resets the "$" jQuery variable. This will make our call fail.

The easiest solution I found is to assign another variable to jQuery using the "jQuery.noConflict()" function.

  <script type="text/javascript" src="js/jquery-1.7.1.min.js"></script>
  <script type="text/javascript" src="js/jquery-plugin.js"></script>
  <script type="text/javascript">

    var $j = jQuery.noConflict();

    function callbackToPlugin() {
      return function () {
        $j('#plugin').callToPlugin();
      };
    }

    </script>

Now, the jQuery variable is "$j" instead of "$". Make sure you call the correct method from the Wicket page.

  @Override
  public void renderHead(IHeaderResponse response) {
    if (callPlugin) {
      response.render(
        OnDomReadyHeaderItem.forScript("$j(document).ready(callbackToPlugin())"));
    }
  }

If you have a better solution for this, please let me know in the comments.

Monday, November 5, 2012

Login twice in Wicket

Since the last time I upgraded my Wicket application, I noticed I had to login twice to be authenticated in the application. After careful research using the number one research tool (Google), I found the cause of this problem. The problem is that my login page is stateless. Wicket will create a temporary dummy session for stateless pages, which will not be saved internally in the session store. The solution is to let the session stick after authentication by calling bind in the session:
@Override
public boolean authenticate(String userName, String password) {
    // Your authentication code here...

    // Only reach this when authenticated...

    if (isTemporary()) {
        bind();
    }
}

Saturday, November 3, 2012

Reload JQuery when DOM is changed by Wicket/AJAX

I'm using many jQuery plugins in my Wicket application. When Wicket AjaxBehaviors change the DOM of the page, the initial changes made by the jQuery plugins are often lost. To solve this, we have to initiate the jQuery plugins again when the AjaxBehavior executes. We can do that by appending the plugin initialization JavaScript code like below:
aTextField.add(new OnChangeAjaxBehavior() {
    @Override
    protected void onUpdate(AjaxRequestTarget target) {
        target.add(aContainerThatIsRefreshed);
        target.appendJavaScript("$('.jQueryPluginClass').initiatePlugin();");
    }
});
Change the ".jQueryPluginClass" CSS class, and ".initiatePlugin()" plugin call for your specific project.

Thursday, July 26, 2012

Custom Wicket FeedbackPanel markup

I had to add custom static markup to the Wickets FeedBackPanel for a project I'm currently working on. The markup has to be visible only when the the feedback panel itself is visible. The easiest way to do this is to extend the original class, and provide a corresponding HTML file with the custom markup.
package com.javaeenotes;

import org.apache.wicket.feedback.IFeedbackMessageFilter;
import org.apache.wicket.markup.html.panel.FeedbackPanel;


public class ErrorPanel extends FeedbackPanel {
    private static final long serialVersionUID = 1L;


    public ErrorPanel(String id, IFeedbackMessageFilter filter) {
        super(id, filter);
    }


    public ErrorPanel(String id) {
        super(id);
    }
}
<wicket:panel>
  <div class="feedbackPanel" wicket:id="feedbackul">
    <b>Error</b>
    <div class="errorlevel" wicket:id="messages">
      <span class="errorlevel" wicket:id="message">A message</span>
    </div>
  </div>
</wicket:panel>
The HTML file is basically the same as the original file. I added an error header as an example.

Friday, December 16, 2011

Running Wicket on Jetty

If you're only using the web functionality provided by an application server, or you want to optimize HTTP performance, it would be a good idea to consider embedding the Jetty HTTP server inside your application. This way, you don't even have to generate a WAR-file and a web.xml file. The application is just a basic Java application, which you can run on any server with a Java VM.

Maven setup

If you're using a Maven project, add the following dependencies to the pom-file in the "dependencies"-element in order to start working right away:

<dependency>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>jetty-hightide</artifactId>
  <version>8.0.4.v20111024</version>
</dependency>

<dependency>
  <groupId>org.apache.wicket</groupId>
  <artifactId>wicket-core</artifactId>
  <version>1.5.3</version>
</dependency>

Minimal Wicket application

For our example, we use a minimal Wicket application that consists of one page.

The ExampleWicketApplication.java file:
package com.javaeenotes;


import org.apache.wicket.Page;
import org.apache.wicket.protocol.http.WebApplication;


public class ExampleWicketApplication extends WebApplication {

    @Override
    public Class<? extends Page> getHomePage() {
        return HomePage.class;
    }
}
The HomePage.java file:
package com.javaeenotes;


import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;


public class HomePage extends WebPage {
    public HomePage() {
        add(new Label("message", "Hello World!"));
    }
}
The HomePage.html file:
<html>
<body>
  <span wicket:id="message"></span>
</body>
</html>

The final class we need is a main class with the static main-method, in which we tie the Wicket servlet to the Jetty server.

The Main.java file:
package com.javaeenotes;


import org.apache.wicket.protocol.http.WicketFilter;
import org.apache.wicket.protocol.http.WicketServlet;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.bio.SocketConnector;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.webapp.WebAppContext;


public class Main {
    public static void main(String[] args) {
        // Object that holds, and configures the WicketServlet.
        ServletHolder servletHolder =
                new ServletHolder(new WicketServlet());
        servletHolder.setInitParameter(
                "applicationClassName",
                "com.javaeenotes.ExampleWicketApplication");
        servletHolder.setInitParameter(
                WicketFilter.FILTER_MAPPING_PARAM, "/*");
        servletHolder.setInitOrder(1);

        // Web context configuration.
        WebAppContext context = new WebAppContext();
        context.addServlet(servletHolder, "/*");
        context.setResourceBase("."); // Web root directory.

        // The HTTP-server on port 8080.
        Server server = new Server();
        SocketConnector connector = new SocketConnector();
        connector.setPort(8080);
        server.setConnectors(new Connector[]{connector});
        server.setHandler(context);

        try {
            // Start HTTP-server.
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Run the main method in a VM, and connect to port 8080 with a browser to check that the application is working.

Saturday, May 14, 2011

Creating a Modal Window page with Apache Wicket

This post aims to clarify creating a modal window with Apache Wicket. Before continuing, minimum basic knowledge about Apache Wicket is required. A modal window is a child window on top of the main window. The modal window requires the user to interact with it, before the user can return to the main window.

The application we're developing consists of two pages:

  • The main page (LaunchPage.java and LaunchPage.html)
  • The modal window page (ModalContentPage.java and ModalWContentPage.html)

The main page defines and displays the content of a variable and it also has a link to open the modal window page.

The modal window page displays the content of the same variable. But when the modal window is closed, the variable is changed by the modal window page.

Let's start by creating the HTML-file of the main page.

<html>
<head>
<title>Launch Page</title>
</head>
<body>
<div wicket:id="modal"></div>
<span wicket:id="passValueLabel">Value of passValue variable.</span>
<a wicket:id="showModalLink">Open modal window.</a>
</body>
</html>

This page defines the modal page with id "modal". The next line is the location where the content of the variable "passValue" is displayed. Finally, a link is defined that opens the modal window.

Next, the corresponding Java class:

package com.javaeenotes;

import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.PropertyModel;

public class LaunchPage extends WebPage {

private String passValue;

@SuppressWarnings("serial")
public LaunchPage() {

passValue = "This value is passed to the modal window.";

// Display the current content of the passValue variable. The
// PropertyModel must be used, as the value can be changed.
final Label passValueLabel;
add(passValueLabel = new Label("passValueLabel",
new PropertyModel<String>(this, "passValue")));
passValueLabel.setOutputMarkupId(true);

// Create the modal window.
final ModalWindow modal;
add(modal = new ModalWindow("modal"));
modal.setCookieName("modal-1");

modal.setPageCreator(new ModalWindow.PageCreator() {
public Page createPage() {
// Use this constructor to pass a reference of this page.
return new ModalContentPage(LaunchPage.this.getPageReference(),
modal);
}
});
modal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
public void onClose(AjaxRequestTarget target) {
// The variable passValue might be changed by the modal window.
// We need this to update the view of this page.
target.add(passValueLabel);
}
});
modal.setCloseButtonCallback(new ModalWindow.CloseButtonCallback() {
public boolean onCloseButtonClicked(AjaxRequestTarget target) {
// Change the passValue variable when modal window is closed.
setPassValue("Modal window is closed by user.");
return true;
}
});

// Add the link that opens the modal window.
add(new AjaxLink<Void>("showModalLink") {
@Override
public void onClick(AjaxRequestTarget target) {
modal.show(target);
}
});
}

public String getPassValue() {
return passValue;
}

public void setPassValue(String passValue) {
this.passValue = passValue;
}
}

The class file displays the content of "passValue" and creates the modal window class with its methods. Look carefully at the code and comments in the modal window methods. We can see that the passValueLabel is expected to change in the window close callback method. We can also see that the variable is actually changed using a setter in the close button callback method. This happens when the user clicks on the close button of the modal window. Finally, an AJAX link is defined and added to the page.

The second part is the modal window page:

<html>
<head>
<title>Modal Content Page</title>
</head>
<body>
<span wicket:id="passValueLabel">Current content of passValue variable.</span>
</body>
</html>

The modal page only displays the content of the "passValue" variable. The variable is owned by the main page.

package com.javaeenotes;

import org.apache.wicket.PageReference;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;

public class ModalContentPage extends WebPage {

public ModalContentPage(final PageReference modalWindowPage,
final ModalWindow window) {

// Retrieve the passValue content for display.
String passValue = ((LaunchPage) modalWindowPage.getPage())
.getPassValue();
add(new Label("passValueLabel", passValue));

// You can use the
// ((LaunchPage)modalWindowPage.getPage()).setPassValue() method to
// change the passValue variable of the launch/caller page.
}
}

This class is pretty simple. The first parameter refers to the main page that created the modal window page. Go back, and look how the modal window page is constructed in the main page. The main page is casted and the variable is retrieved using the getter-method. The content is then displayed in the modal window page.

Now run the code and the main page will look like this:



After clicking the link, the modal window page is opened:



We can see the same variable is displayed in the modal window page. Now, we close the modal window page. Because of this event, the variable is changed as instructed in the callback code:



As expected, the variable is changed in the main window.