My blog has moved!

You will be automatically redirected to the new address. If that does not occur, visit
http://utku-utkan.appspot.com/
and update your bookmarks.

Pages

Thursday, July 26, 2007

Dynamic Forms in Wicket

The Dynamic Form Application is an example Wicket application to demonstrate forms with varying number of input fields. This application has only one page which contains the form having varying number of input fields to enter the words, and another input field to display the sentence composed from the entered words. The number of the fields is determined randomly at page refresh. When the user submits the form the sentence composed from the words is displayed.



In this example, you have to put all files in the same package directory. This means putting the markup files and the java files next to one another. It is possible to alter this behavior, but that is beyond the scope of this example.

Word.java
Word is a just a serializable POJO defining the properties that are associated with UI components used on the page. In our simple example, Word has only one property named text.

package com.hoydaa.dynamicform;

import java.io.Serializable;

public class Word implements Serializable {

    private static final long serialVersionUID = 1L;

    private String text;

    public Word(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}


DynamicFormPage.java
DynamicFormPage is a class of type WebPage, which is also the homepage of the application. In this class, Wicket components are added to the page just like the Swing components are being added to a Swing frame.

Inside the constructor of DynamicFormPage, DynamicForm - which is a Form component - is added to the page with the ID of "form".

Inside the constructor of the DynamicForm, a TextArea component with the ID of "sentence" is added to the form in order to store the sentence composed from the words. This component is bounded to the sentence attribute of the DynamicForm via PropertyModel.

Since there will be several words; there must be a list to store these words. Initially this list is created with random number of empty Words. Later on, a ListView component is added to form. Well, all the magic is here. ListView calls the populateItem method for each of the words. As a result, a TextField component is added to the form for each of the Words inside the words list.

Finally, onSubmit method of the Form class is overridden in order to set the sentence to the composition of the words.

package com.hoydaa.dynamicform;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import wicket.PageParameters;
import wicket.markup.html.WebPage;
import wicket.markup.html.form.Form;
import wicket.markup.html.form.TextArea;
import wicket.markup.html.form.TextField;
import wicket.markup.html.list.ListItem;
import wicket.markup.html.list.ListView;
import wicket.model.PropertyModel;

public class DynamicFormPage extends WebPage {

    private static final long serialVersionUID = 1L;

    public DynamicFormPage(PageParameters params) {
        add(new DynamicForm("form"));
    }

    public class DynamicForm extends Form {

        private static final long serialVersionUID = 1L;

        private String sentence;
        private List words;

        public DynamicForm(String id) {
            super(id);

            TextArea textArea = new TextArea("sentence", new PropertyModel(this, "sentence"));
            textArea.setOutputMarkupId(true);
            add(textArea);

            Random random = new Random();
            int numberOfFields = random.nextInt(4) + 1;

            words = new ArrayList();

            for (int i = 0; i < numberOfFields; i++) {
                words.add(new Word(""));
            }

            add(new ListView("list", words) {

                private static final long serialVersionUID = 1L;

                @Override
                protected void populateItem(ListItem item) {
                    final Word word = (Word) item.getModelObject();

                    TextField textField = new TextField("word", new PropertyModel(word, "text"));
                    textField.setOutputMarkupId(true);
                    item.add(textField);
                }
            });
        }

        public String getSentence() {
            return sentence;
        }

        public void setSentence(String sentence) {
            this.sentence = sentence;
        }

        @Override
        protected void onSubmit() {
            StringBuffer strBuff = new StringBuffer();

            for (Word word : words) {
                strBuff.append(word.getText());
                strBuff.append(" ");
            }

            sentence = strBuff.toString();
        }
    }
}


DynamicFormPage.html
This html is the markup file for the DynamicFormPage class. In this html, there is a matching html element for every component added to the DynamicFromPage. Inside the body tag there is the form element for the corresponding form component. The first input element of this form is the sentence text area, which is to display the sentence composed from the values entered to the word text inputs. Right after the sentence text area, there is a div element that will be iterated with its content. The content of this iteration element is just a text input to fetch the words from the user. And the last element is the submit button.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:wicket="http://wicket.sourceforge.net">
    <head>
        <title>Dynamic Form Application</title>
    </head>
    <body>
        <form wicket:id="form">
            <textarea wicket:id="sentence"></textarea>
            <div wicket:id="list">
                <input wicket:id="word" type="text"/>
            </div>
            <input type="submit" value="Print"/>
        </form>
    </body>
</html>


DynamicFormApp.java
In Wicket, there must be an application class to declare application wide settings such as the homepage of the application. In this example, getHomePage method of the WebApplication base class is overridden to return DynamicFormPage.class as the homepage.

package com.hoydaa.dynamicform;

import wicket.protocol.http.WebApplication;

public class DynamicFormApp extends WebApplication {

    @Override
    public Class getHomePage() {
        return DynamicFormPage.class;
    }
}


web.xml
Any Wicket Web application requires a Servlet definition to initialize the framework. The name of the application class that is presented above must be declared as an initialization parameter to this Servlet definition.

<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>dynamicform</display-name>

    <servlet>
        <servlet-name>DynamicFormApplication</servlet-name>
        <servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>com.hoydaa.dynamicform.DynamicFormApp</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DynamicFormApplication</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
</web-app>

No comments: