Introduction

Click is a simple JEE web application framework for commercial Java developers.

Click is an open source project, licensed under the Apache license.

Click uses an event based programming model for processing Servlet requests and Velocity for rendering the response. (Note other template engines such as JSP and Freemarker are also supported)

This framework uses a single servlet, called ClickServlet, to act as a request dispatcher. When a request arrives ClickServlet creates a Page object to process the request and then uses the page's Velocity template to render the results.

Pages provide a simple thread safe programming environment, with a new page instance created for each servlet request.

Possibly the best way to see how Click works is to dive right in and look at some examples:

  1. Hello World - the Hello World classic
  2. Control Listener - a ActionLink control listener example
  3. Simple Table - a simple Table control example
  4. Advanced Table - a more advanced Table example
  5. Simple Form - a simple Form example
  6. Advanced Form - a more advanced Form example
These examples are available online at http://www.avoka.com/click-examples/ under the menu "Intro Examples".

 

1.  Hello World Example

A Hello World example in Click would look something like this.

First we create a HelloWorld page class:

package examples.page;

import java.util.Date;
import net.sf.click.Page;

public HelloWorld extends Page {

    public Date time = new Date();

} 
Next we have a page template hello-world.htm:
<html>
  <body>
  
    <h2>Hello World</h2>
    
    Hello world from Click at $time
    
  </body>
</html> 
Click is smart enough to figure out that the HelloWorld page class maps to the template hello-world.htm. We only have to inform Click of the package of the HelloWorld class, in this case examples.page.

We do that through the click.xml configuration file which tells Click to map hello-world.htm requests to our examples.page.HelloWorld page class.

<click-app>  
  <pages package="examples.page"/> 
</click-app> 

At runtime the ClickSerlvet maps a GET hello-world.htm request to our page class example.page.HelloWorld and creates a new instance. The HelloWorld page creates a new public Date object, which is automatically added to the pages model using the fields name time.

The page model is then merged with the template which substitutes the $time parameter with the Date object. Velocity then renders the merged template which looks something like

Hello World

Hello world from Click at Tue May 08 19:37:05 EST 2007

 

2.  Control Listener Example

Click includes a library of Controls which provide user interface functionality.

One of the commonly used controls is the ActionLink, which you can use to have a HTML link call a method on a Page object. For example:

public class ControlListenerPage extends Page {

    public ActionLink myLink = new ActionLink();

    public String msg;
    
    // ----------------------------------------------------------- Constructors

    /**
     * Create a new Page instance.
     */
    public ControlListenerPage() {
        myLink.setListener(this, "onMyLinkClick");
    }
    
    // --------------------------------------------------------- Event Handlers

    /**
     * Handle the myLink control click event.
     */
    public boolean onMyLinkClick() {
        msg = "ControlListenerPage#" + hashCode()
            + " object method <tt>onMyLinkClick()</tt> invoked.";

        return true;
    }
} 
In the Page class we create an ActionLink called myLink and define the control's listener to be the page method onMyLinkClick(). When a user clicks on myLink control it will invoke the listener method onMyLinkClick().

In Click a control listener method can have any name but it must return a boolean value. The boolean return value specifies whether processing of page events should continue. This control listener pattern provides a short hand way for wiring up action listener methods without having to define anonymous inner classes.

Back to our example, in the page template we define a HTML link and have the myLink control render the link's href attribute:

<html>
  <head>
    <link type="text/css" rel="stylesheet" href="style.css"></link>
  </head>
  <body>
  
  Click myLink control <a href="$myLink.href">here</a>.

  #if ($msg)
    <div id="msgDiv"> $msg </div>
  #end

  </body>
</html>
At runtime this page would be rendered as:
Click myLink control here.
When a user clicks on the link the onMyLinkClick() method is invoked. This method then creates msg model value, which is rendered in the page as:
Click myLink control here.
ControlListenerPage#12767107 object method onMyLinkClick() invoked.

 

3.  Simple Table Example

One of the most useful Click controls is the Table control.

An example usage of the Table control in a customers Page is provided below:

public class SimpleTablePage extends Page {

    public Table table = new Table();

    // ------------------------------------------------------------ Constructor
     
    public SimpleTablePage() {
        table.setClass(Table.CLASS_ITS);
        
        table.addColumn(new Column("id"));
        table.addColumn(new Column("name"));
        table.addColumn(new Column("email"));
        table.addColumn(new Column("investments"));
    }
    
    // --------------------------------------------------------- Event Handlers
     
    /**
     * @see Page#onRender()
     */
    public void onRender() {
    	List list = getCustomerService().getCustomersSortedByName(10);
    	table.setRowList(list);
    }
} 
In this Page code example a Table control is declared, we set the table's HTML class, and then define a number of table Column objects. In the column definitions we specify the name of the column in the constructor, which is used for the table column header and also to specify the row object property to render.

The last thing we need to do is populate the table with data. To do this we override the Page onRender() method and set the table row list before it is rendered.

In our Page template we simply reference the $table object which is rendered when its toString() method is called.

<html>
<head>
$cssImports
</head>
<body>
  
$table
    
</body>
</html> 
$jsImports
Note above we also specify the $cssImports reference so the table can include any CSS imports or styles in the header, and the $jsImports reference any JavaScript imports or scripts at the bottom.

At runtime the Table would be rendered in the page as:

 

4.  Advanced Table Example

The Table control also provides support for: A more advanced Table example is provided below:
public class CustomerPage extends Page {

    public Table table = new Table();
    public PageLink editLink = new PageLink("Edit", EditCustomer.class);
    public ActionLink deleteLink = new ActionLink("Delete", this, "onDeleteClick");

    // ------------------------------------- Constructor
     
    public CustomersPage() {
        table.setClass(Table.CLASS_ITS);
        table.setPageSize(10);
        table.setShowBanner(true);
        table.setSortable(true);
    	
        table.addColumn(new Column("id"));

        table.addColumn(new Column("name"));
        
        Column column = new Column("email");
        column.setAutolink(true);
        column.setTitleProperty("name");
        table.addColumn(column);
        
        table.addColumn(new Column("investments"));
        
        editLink.setImageSrc("/images/table-edit.png");
        editLink.setTitle("Edit customer details");
        editLink.setParameter("referrer", "/introduction/advanced-table.htm");
        
        deleteLink.setImageSrc("/images/table-delete.png");
        deleteLink.setTitle("Delete customer record");
        deleteLink.setAttribute("onclick", "return window.confirm('Are you sure you want to delete this record?');");
    	
        column = new Column("Action");
        column.setTextAlign("center");
        AbstractLink[] links = new AbstractLink[] { editLink, deleteLink };
        column.setDecorator(new LinkDecorator(table, links, "id"));
        column.setSortable(false);
        table.addColumn(column);
    }
    
    // ---------------------------------- Event Handlers
         
    /**
     * Handle the delete row click event.
     */    
    public boolean onDeleteClick() {
        Integer id = deleteLink.getValueInteger();
        getCustomerService().deleteCustomer(id);
        return true;
    }
    
    /**
     * @see Page#onRender()
     */
    public void onRender() {
    	List list = getCustomerService().getCustomersByName();
    	table.setRowList(list);
    }
} 
In this Page code example a Table control is declared and a number of Column objects are added. A deleteLink ActionLink control is used as a decorator for the "Action" column. This control will invoke the Page onDeleteClick() method when it is clicked. Finally we have the Page onRender() method which is used to populate the Table control with rows before it is rendered.

In our Page template we simply reference the $table object which is rendered when its toString() method is called.

<html>
<head>
$cssImports
</head>
<body>
  
$table
    
</body>
</html>
$jsImports 
At runtime the Table would be rendered in the page as:
In this example if a user click on the Delete link the onDeleteClick() method will be called on the Page deleting the customer record.

 

5.  Simple Form Example

The Form and Field controls are also some of the most commonly used controls in the Click Framework.

The SimpleForm page below provides a demonstration of using these controls.

In our example code we have the page's constructor adding a TextField field and a Submit button to the form. A page method is also set as a control listener on the form. Also note in this example the page's public form field is automatically added to its list of controls.

public class SimpleForm extends Page {

    public Form form = new Form();
    public String msg;

    // ------------------------------------------------------------ Constructor

    public SimpleForm() {
        form.add(new TextField("name", true));
        form.add(new Submit("OK"));

        form.setListener(this, "onSubmit");
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * Handle the form submit event.
     */
    public boolean onSubmit() {
        if (form.isValid()) {
            msg = "Your name is " + form.getFieldValue("name");
        }
        return true;
    }
}

Next we have the SimpleForm template simple-form.htm. The Click application automatically associates the simple-form.htm template with the SimpleForm class.

<html>
<head>
$cssImports
</head>
<body>
  
$form
  
#if ($msg)
  <div id="msgDiv"> $msg </div>
#end
    
</body>
</html> 
$jsImports
When the SimpleForm page is first requested the $form object will automatically render itself as:
*
Say the user does not enter their name and presses the OK button to submit the form. The ClickServlet creates a new SimpleForm page and processes the form control.

The form control processes its fields and determines that it is invalid. The form then invokes the listener method onSubmit(). As the form is not valid this method simply returns true and the form renders the field validation errors.

You must enter a value for Name
*
Note the form will automatically maintain the entered state during the post and validate cycle.

Now if the user enters their name and clicks the OK button, the form will be valid and the onSubmit() add a msg to the Pages model. This will be rendered as:

*
Your name is John Masters

 

6.  Advanced Form Example

The AdvancedForm page below provides a more advanced demonstration of using Form, Field and FielsSet controls.

First we have an AdvancedForm class which setups up a Form in its constructor. The form's investment Select list is populated in the page's onInit() method. At this point any page dependencies such as the CustomerService should be available.

Note in this example the page's public form field is automatically added to its list of controls. The msg field is added to the page's model.

public class AdvancedForm extends Page {

    public Form form = new Form();
    public String msg;

    private Select investmentSelect = new Select("investment");

    // ------------------------------------------------------------ Constructor

    public AdvancedForm() {
        FieldSet fieldSet = new FieldSet("Customer");
        form.add(fieldSet);

        TextField nameField = new TextField("name", true);
        nameField.setMinLength(5);
        nameField.setFocus(true);
        fieldSet.add(nameField);

        fieldSet.add(new EmailField("email", true));

        fieldSet.add(investmentSelect);

        fieldSet.add(new DateField("dateJoined", true));
        fieldSet.add(new Checkbox("active"));

        form.add(new Submit("ok", " OK ", this, "onOkClicked"));
        form.add(new Submit("cancel", this, "onCancelClicked"));
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * @see Page#onInit()
     */
    public void onInit() {
        CustomerService customerService = getCustomerService();
        investmentSelect.add(Option.EMPTY_OPTION);
        investmentSelect.addAll(customerService.getInvestmentCatetories());
    }

    /**
     * Handle the OK button click event.
     *
     * @return true
     */
    public boolean onOkClicked() {
        if (form.isValid()) {
            Customer customer = new Customer();
            form.copyTo(customer);

            getCustomerService().saveCustomer(customer);

            form.clearValues();

            msg = "A new customer record has been created.";
        }
        return true;
    }

    /**
     * Handle the Cancel button click event.
     *
     * @return false
     */
    public boolean onCancelClicked() {
        setRedirect(HomePage.class);
        return false;
    }
}
Next we have the AdvancedForm template advanced-form.htm. The Click application automatically associates the advanced-form.htm template with the AdvancedForm class.
<html>
<head>
$cssImports
</head>
<body>

#if ($msg)
  <div id="msgDiv"> $msg </div>
#end
  
$form
    
</body>
</html> 
$jsImports
When the AdvancedForm page is first requested the $form object will automatically render itself as:
Customer
*
*
 
* Calendar
 
In this example when the OK button is clicked the onOkClicked() method is invoked. If the form is valid a new customer object is created and the forms field values are copied to the new object using the Form copyTo() method. The customer object is then saved, the form's field values are cleared and an info message is presented to the user.

If the user clicks on the Cancel button the request is redirected to the applications HomePage.

6.1  Form Layout

In the example above the Form control automatically renders the form and the fields HTML markup. This is a great feature for quickly building screens, and the form control provides a number of layout options. See the Click Examples for an interactive Form Properties demo.

For fine grained page design you can specifically layout form and fields in your page template. See the Template Layout section and Form Javadoc for more details.

An alternative approach to page template design is using a programmatic approach. See the Programmatic Layout section for more details.