Part four: Making the UI with jQuery and Freemarker

This is the fourth and final part of my Minesweeper portlet tutorial.

This part focuses on the html side of the portlet and shows how we use jQuery and freemarker to make our UI dynamic.

Implementing the hover effect

First we will show how the jQuery javascript library is used to get a hover effect on the squares in the game board. The liferay portal 5.2.3 comes built-in with jQuery version 1.2.6, which is slightly dated but works in most cases. In liferay the used notation is jQuery() instead of the normal $() used in the jQuery documentation.

The freemarker template _game_board.ftl contains the following javascript which changes the class of the <td> element on hover.
jQuery(document).ready(function() {
        function() {
            if (jQuery(this).hasClass("not-clicked")) {
        function() {
            if (jQuery(this).hasClass("not-clicked-hover")) {
With the following style definitions in minesweeper.css
.not-clicked {
    background-image: url('../images/button.png');

.not-clicked-hover {
    cursor: pointer;
    background-image: url('../images/button_hover.png');
we get the desired effect.

Doing the click with Ajax

Next we will see how we can update parts of the html using Ajax. We are going to use jQuery for that also.

First lets look at the following snippet of javascript from _game_board.ftl
jQuery(document).ready(function() {
    jQuery(".game-board .not-clicked").click(function() {        
Here we use jQuery selectors to bind a handler for the click event on those squares, which are not yet clicked. The actual event handling code does first the following:
        var x = jQuery(this).attr("xloc");
        var y = jQuery(this).attr("yloc");
        var url = '<@s.url action="click"/>';
The attributes xloc and yloc contain the x and y coordinates of the square. Then we use the freemarker built in @s.url taglib to get the url for the click action.

Next line in the click handler changes the p_p_state parameter value to exclusive:
        url = url.replace('p_p_state=normal', 'p_p_state=exclusive');
The exclusive tells liferay that the page should be loaded without any of the layout html that is normally used. Finally we have
        jQuery("#game-board-container").load(url, {x: x, y: y});
which loads the click result to the <div> containing the game board.



  1. Thanks for excellent tutorial. Tried to deploy minesweeper in liferay-6.0.4. Everything worked fine and game is deployed successfully. The problem is that game is not working, what may be the reason of that.

  2. I haven't tried the portlet with liferay 6. I'll have to check out what the problem could be.

  3. I have made an updated version of the tutorial for liferay 6, you can find the explanation and sources here: