Control-Writing Guide
From JWic
Working with jWic means working with controls, making it essential to have a good knowlege how to design a control. This guide helps new and experienced users to get a good understanding how controls work, how they are designed and what limitations they have.
Contents |
Preface
You should have already created a new and jWic-ready project in your favorit IDE to start writing the controls and samples specified in this guide. You find more infos about these things in the development setup guide.
To test the controls in this guide, you need an application where you can create and test the controls. The first step tutorial is a good entry point to get a basic understanding how to create that application. It is recommended that you read this tutorial before you start with this guide.
The source code for the code in this guide will be available for download soon.
Basic Rules
Control design follows a few specific rules, that you should keep in mind when you create a new control.
- A control should not depend on a specific container
- A control should not be limited to be the only instance on a page
- A control should be serializable
jWic helps the developer in various ways to archive these goals easily. How this is done will be explained in the following chapters.
Simple Controls
Display a Color Box
A control represents a part on a webpage that can display information and can interact with the user. The following control will simply display a small box. The color of the box will be specified by a property of the control. The UML diagramm of the control looks rather simple:
Next step is to create the java class ColorBoxControl in our package de.jwic.guide.simple. The class must extend the de.jwic.base.Control class. The initial code looks like this:
package de.jwic.guide.simple;
import de.jwic.base.Control;
import de.jwic.base.IControlContainer;
public class ColorBoxControl extends Control {
public ColorBoxControl(IControlContainer container, String name) {
super(container, name);
}
public void actionPerformed(String actionId, String parameter) {
}
}
Now we need a property for the color of the box. For simplicity, we will store the color as a simple string that is used as the argument for the css background-color property. Controls are designed following the JavaBeans pattern, so we add a private field color and the appropriate getter and setter methods:
public class ColorBoxControl extends Control {
private String color = "black";
public ColorBoxControl(IControlContainer container, String name) {..}
public void actionPerformed(String actionId, String parameter) {..}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
requireRedraw();
}
}
Notice that the setColor method calls requireRedraw to mark itself as 'dirty'. The AJAX based rendering engine needs this information to know which controls to update and which not. If you forget this line of code, the control will not get updated when some code changes this property.
The java part is now finished, but we need a template where we specify the HTML code that will reflect the control on the page. Create a new file in the same package with the name of the control but with a '.vtl' extension at the end: ColorBoxControl.vtl
To display the color, we simply display a div element and set the background-color property to the one specified in our controls property. The code looks like this:
<div style="background-color: $control.color; width: 50px; height: 50px;"></div>
Our control is ready for testing now. Create a new Application class and an .xwic file to launch this application. My testcode for the color control looks like this:
public class TestColorBoxApplication extends Application {
public Control createRootControl(IControlContainer container) {
Page page = new Page(container);
page.setTitle("Color Test");
TableLayoutContainer tbl = new TableLayoutContainer(page);
tbl.setColumnCount(2);
String colors[] = { "red", "green", "blue", "#FFF221" };
for (int i = 0; i < colors.length; i++) {
new LabelControl(tbl).setText(colors[i]);
ColorBoxControl colorBox = new ColorBoxControl(tbl, null);
colorBox.setColor(colors[i]);
}
return page;
}
}
Bean Viewer Control
In the previous control, we had just one property that was used to define the color of a box. The color was represented by a simple String but more complex objects work just alike. Your control would also have a property for the bean, i.e.:
public Product getProduct(IProduct product) {
return product;
}
public void setProduct(IProduct product) {
this.product = product;
requireRedraw();
}
The template can display the bean properties like this:
<table> <tr> <td>Name</td> <td>$control.product.name</td> </tr> <tr> <td>Description</td> <td>$conrol.product.description</td> </tr> </table>
Hint: If you want to display an objects properties, this way is recommended. Creating a container and adding a LabelControl for each property is much more effort and overhead.
Interactive Controls
There are several ways how an application can interact with the user, but the most common way (in the web) is that a user clicks somewhere with his pointer (i.e. mouse). On a normal website, these actions let the browser go to a page specified in a link. In a jWic application, such an action triggers a JavaScript function that handles the submit so that the control, that generated the code for the action, gets notified.
It is a very important feature of jWic, that controls do not handle POST/GET requests on their own. The jWic client library takes care of all fields and controls on the form. This makes controls "independent" from other controls on the same page, allowing you to (re-)use controls in many places.
But lets do a little example to see how it works.
Recieving actions from the user
For the sake of simplicity, we will build a color picker that is based upon the ColorBoxControl. We will create our own template that contains some action links and implement the actionPerformed(..) method to handle color selections.
Create a new class named ColorPickControl that extends ColorBoxControl and create a new template file ColorPickControl.vtl with the following content:
<div style="background-color: $control.color; width: 50px; height: 50px;"></div>
<a href="$control.createActionURL("setColor", "red")">Red</a> |
<a href="$control.createActionURL("setColor", "blue")">Blue</a> |
<a href="$control.createActionURL("setColor", "green")">Green</a>
The HTML code that is generated for an anchor link looks like this:
<a href="javascript:jWic().fireAction('controlId', 'setColor', 'red')">Red</a>
If the user hits this link, jWic submits the page (via ajax) and invokes the controls actionPerformed method together with the two parameters 'setcolor' and 'red'. Therefore we have to override the actionPerformed method and handle the action:
public class ColorPickControl extends ColorBoxControl {
public ColorPickControl(IControlContainer container, String name) {
super(container, name);
}
public void actionPerformed(String actionId, String parameter) {
if (actionId.equals("setColor")) {
setColor(parameter);
}
}
}
UPDATE: Since version 3.0.4, jWic support an auto-mapping of actions. Since this version, the actionPerformed method in Control is no longer abstract. So if you do not override it (or just call super..), the actionId is mapped to a method that begins with 'action', followed by the actionId name. So the sample code would now look like this:
public class ColorPickControl extends ColorBoxControl {
public ColorPickControl(IControlContainer container, String name) {
super(container, name);
}
public void actionSetColor(String newColor) { //maps to 'setColor' action
setColor(newColor);
}
}
If you want to trigger an action within a JavaScript, you can directly call the fireAction javaScript function, but you must add the controlID as first argument so that jWic finds the control within the control hierachy.
<select size="10"
ondblclick="if(confirm("Are you sure?"))jWic().fireAction('$control.controlID', 'dblclick', '')">
...
Field Access
HTML allows us to place elements on a page where the user can enter data or select an option from a list. Those fields are grouped by a <form> tag, so that all fields on a form can be submited to the server for further processing. A jWic control does not have to deal with a form, because a control is already surrounded by a form, which is managed by jWic.
The server side representation of a field is the Field object, which stores the value of the field on the page. When a submit occures, the value send by the client is written into this field object.
TextBox
A simple text control looks like this (the relevant parts are highlighted):
public class TextControl extends Control {
private Field field;
public TextControl(IControlContainer container, String name) {
super(container, name);
field = new Field(this);
}
public Field getField() {
return field;
}
}
The template looks like this:
<input type="text" name="$control.field.id" value="jwic.formatInp($control.field.value)">
And the generated HTML code will look like this:
<INPUT name="fld_c0.c0.c0.0" value="123">
In this sample, we have added a getField() method to access the field within our template. If you do not like to have such a public method, you may also work with named fields. In this case, the field should be instanciated like this:
field = new Field(this, "myfield");
Now you can access the field in the template by its name:
<input type="text" name="$control.getField("myfield").id" value="$jwic.formatInp($control.getField("myfield").value)">
The control is now able to store and access the field value. Users of the control might now access the field values as well, but it is highly recommended NOT to do that. Fields belong to the internals of a control and should not be accessed outside the control, except the framework itself and renderer implementations. To allow users of the control to access the value, we add a getter/setter pair for the field:
public String getText() {
return field.getValue();
}
public void setText(String text) {
field.setValue(text);
requireRedraw();
}
Communication with other controls
Controls are designed by the JavaBeans pattern and therefore, they use events to communicate with other controls. Controls may fire events, which means the control sends an event to other controls.
Since the JavaBeans event model is well known and specified, we see no need to do it here again. If you are not familiar with the event model, we suggest that you download the JavaBeans Specification and have a look into chapter 6 Events.
We just want to remind you that a control should never invoke method of it's containers directly. Code like the following is a bad design as you may not reuse the control in other containers:
public void someAction() {
EditorContainer editor = (EditorContainer)getContainer();
editor.doSave();
}
Using JavaScript
Controls may generate JavaScript code to add functionality to their UI elements. Due to the nature of controls and how they get updated via AJAX, there are a few things to obey.
document.write()
With the document.write() method, you can generate HTML code from JavaScript. Some JavaScript libraries use this method to render elements during page load. While this works well, it fails when elements are updated via AJAX. The AJAX update is done by replacing the html-code/elements after the page is already loaded using the innerHtml property. After the html code is updated, the engine invokes JavaScript in the update if it finds any. If this code now contains a document.write() command, the browser will create a new webpage and all that you see will be this:
[object]
Because of this it should be avoided to use this function. If you have to use a library that generates the HTML code, better use the innerHtml property in your template like this:
<span id="marker_${control.controlID}"></span>
<script>
var html = generateMyCode();
// document.write(html); // dont use it!
document.getElementById("marker_${control.controlID}").innerHtml = html;
</script>
Custom Functions
Custom functions are JavaScript functions that are specified within the template and usualy called from within an event code like this:
<button onClick="myFunction()">Hit Me</button>
<script>
function myFunction() {
// do something big
}
</script>
Due to the nature of the AJAX updates and control rules, you must take care of two things:
- Assign the functions to the window object.
- Generate a unique name for the function so that it does not conflict if there are more instances of the same control on one page.
The jWic client executes JavaScript that is found in the updates by calling eval() on the extracted code (in IE only). When you specify a function within an eval() call, the function is bound to the context created for this eval() call and gets lost. To avoid this, you must assign the function directly to the window object:
<button onClick="myFunction()">Hit Me</button>
<script>
window.myFunction = function() {
// do something big
}
</script>
The problem that remains now is the unique name. A good solution to fix that is to add the controlID to the function name. But before we can use the ID, we must replace the '.' characters by '_' as a dot is not allowed in a function name. This can be done with a new function in our control code:
public String getUniqueID() {
return getControlID().replace('.', '_');
}
The template code can then generate unique function names:
<button onClick="myFunction_${control.uniqueID}()">Hit Me</button> <script> window.myFunction_${control.uniqueID} = function() { // do something big } </script>
Testing
Controls are easily testable. Read the Control Unit Tests guide for the details.


