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.