Tutorial - An Introduction To Objective Html
Author Keith Wong, keithwong@optushome.com.au
Last updated: 15th Dec 01
Example Code
These are the files for this example.
customer.jsp [source code]
CustomerForm.java [source code]
The binaries can be downloaded below (packaged in a war file). In Tomcat, simple place the war file under
the "webapps" directory, it will automatically explode when Tomcat is started up.
Make sure the objectivehtml-java-alphaX.jar is in the Tomcat $TOMCAT_HOME/lib directory.
You should then be able to view the
form using the URL http://localhost:8080/objectivehtml/customer.jsp. Replace the server address
and port number if your computer is setup differently.
objectivehtml.war
Introduction
This tutorial gives an introduction into the basic concepts of Objective Html and how you can use it to build interactive html forms.
The form in this tutorial is a typical customer details form.
The customer form has 4 mandatory fields, the Title, the First Name, the Last Name and the Email. If any of mandatory fields are not entered then a error message is displayed and the fields are highlighted.
If the details are successfully saved then a confirmation message is displayed.
Code Walk-Through
CustomerForm.java
import objectivehtml.htmlwidget.*;
import objectivehtml.htmlwidget.exception.*;
You will need to include these 2 packages to start using the toolkit. The objectivehtml.htmlwidget package contains all the HtmlWidget classes.
public class CustomerForm extends HtmlForm
The HtmlForm class as its name suggests represents a html form (<form>). Here we create a new class that extends HtmlForm so we can write our own custom html form. The HtmlForm is the top-most object in the Objective Html class hierarchy. All the other HtmlWidgets must exist inside a HtmlForm object.
public HtmlParagraph m_parUserMessage;
public HtmlTable m_tblLayout;
public HtmlText m_htmUserMessage;
.
.
.
public HtmlTextBox m_txtFirstName;
Our CustomerForm object contains a number of HtmlWidgets. These are all declared as member variables so we can access these objects in our methods later on. I've made the members public so they can be accessed by other classes (mainly by the Jsp page). This is just for convenience sake, you can make them private if you wish. The HtmlWidgets that are used in this form are HtmlParagraph, HtmlTable, HtmlText, HtmlTextBox, HtmlRadioButton, HtmlListBox, HtmlPushButton and HtmlCheckBox.
public CustomerForm()
throws Exception
{
super();
The constructor for our class does not take any arguments and calls the default constructor of HtmlForm which also doesn't take any arguments. The constructor throws the generic Exception class. This was used just for simplicity but you can explicity throw all the exceptions thrown by the HtmlWidget objects. The constructor for our customer form will create all the HtmlWidgets that will be contained inside this form.
setMethod("post");
This method sets the "method" attribute of the HtmlForm object. For our CustomerForm object we are using the post method to submit data.
m_parUserMessage = new HtmlParagraph(this);
Here we create a HtmlParagraph object, which represents a paragraph element (<p>). The object is used to organise html text or widgets into paragraph blocks. The parent for this object is the HtmlForm object. This means the <paragraph> element will exists in its parent element, i.e. the <form> element. All HtmlWidget objects must have a HtmlContainerWidget object as its parent. The HtmlContainerWidget class is used to model html elements that contain other html elements.
m_parUserMessage.setVisible(false);
The visible flag indicates whether a HtmlWidget object is shown or not. The above line sets the HtmlParagraph object to be invisible.
m_htmUserMessage = new HtmlText(m_parUserMessage);
Now we construct a HtmlText object with the HtmlParagraph object as its parent. Because the parent of this widget is invisible this object will also be invisible. A HtmlWidget object cannot be made visible if its parent is invisible. Unlike the other HtmlWidgets in the toolkit, this HtmlText object doesn't really represent any specific html element. There are generally 2 purposes this object can be used for. The first purpose is simply to use the object to get plain text into the form. The second purpose is when you need to include specific html code in the form. In this case we are using the object to provide us with a way to display system messages to the user.
m_tblLayout = new HtmlTable(this, 13, 2);
m_tblLayout.setBorder("0");
m_tblLayout.setBgColor("#FCFADA");
m_tblLayout.setClassAttribute("normal");
The next object that is created is the HtmlTable object. The object represents the <table> element and is the most complex HtmlWidget in the toolkit. The widget is used to organise other widgets in a tabular fashion. The HtmlTable object contains HtmlTableRow and HtmlTableCell objects, these objects can only be created inside a HtmlTable object. The HtmlTable constructor called takes in 3 arguments, the arguments are a reference to its parent and the initial number of rows and columns. This table object is created with 13 rows and 2 columns. The 3 setter methods set the "border", "bgcolor" and "class" attributes of the <table> element. The "border" attribute indicates the pixel width of the border surrounding the table, here we choose to have no border. The "bgcolor" attribute represents the background color of the table. The values given are in RGB. The last attribute "class", is a style-sheet related attribute. By setting the HtmlTable to be in the style-sheet class "normal", the object will inherit display properties of the "normal" class set in the style-sheets of the html page.
m_tblLayout.getTableCell(1, 0).setText("First Name *");
We set the text for the table cell at (0,0). All HtmlContainerWidget objects can either be in text-mode or normal-mode. Text-mode is automatically turned on when the container has no children widgets and has text set for it. This just provides a convenient way to insert text or html code into the form.
m_selTitle = new HtmlListBox(m_tblLayout.getTableCell(0, 1), "m_selTitle");
m_selTitle.addOption("", "- Choose Title -");
m_selTitle.addOption("01", "Mr");
m_selTitle.addOption("02", "Miss");
m_selTitle.addOption("03", "Ms");
m_selTitle.addOption("04", "Mrs");
m_selTitle.setSelected(0, true);
The HtmlListBox object represents the <select> element. The widget allows the user to select a value from a set list of values. The constructor for the HtmlListBox class takes a reference to the parent widget and a control name. All HtmlControlWidget objects need to have a unique control name (the exception being the HtmlRadioButton object). The control name is how the object is identified in the html form and is how the submitted data from the form gets bound to the correct object. Options can be added to the HtmlListBox object by calling the addOption(value,text) method. The first parameter represents the actual value of the option, the second parameter represents the text that is displayed to the user. The values for the options need to be unique otherwise the object will not be able to correctly identify which option is selected. Here we set the first option as selected using the setSelected(index,on) method.
m_txtFirstName = new HtmlTextBox(m_tblLayout.getTableCell(1, 1), "m_txtFirstName");
This will create a HtmlTextBox object inside the table cell at (1,1). The widget allows users to enter text data. As with all HtmlControlWidget objects it requires a unique control name.
m_txtFirstName.setAttribute("size", "20");
There are 2 ways an attribute can be set. You can either set it with the explicit wrapper methods or you can use the generic methods setAttribute(name,value) and setBooleanAttribute(name,on). Here we set the "size" attribute of the HtmlTextBox to 20, this sizing is relative to browser you are displaying this on. Browsers usually take this to mean the HtmlTextBox will have the visual width of 20 times the width of a standard character in the current font. Attribute values are always entered as String values and attribute names are case-insensitive.
m_radMale = new HtmlRadioButton(m_tblLayout.getTableCell(4, 1), "m_radGender");
m_radMale.setValue("M");
m_radMale.setBooleanAttribute("checked", true);
.
.
.
m_radFemale = new HtmlRadioButton(m_tblLayout.getTableCell(4, 1), "m_radGender");
m_radFemale.setValue("F");
Lets skip some lines are go to another more interesting part of the code. In the above code snippet, we create 2 HtmlRadioButton objects, one to represent the male gender and other to represent the female gender. A group of HtmlRadioButtons allows the user to select one of many options. Like all HtmlControlWidgets, the class constructor accepts a reference to the parent and a unique control name. However, the uniqueness of the name only needs to be in the context of other HtmlControlWidget objects that are not also HtmlRadioButton objects. When HtmlRadioButtons are given the same name, like we have here, they are grouped together and will interact with each other. In a group of HtmlRadioButton objects only one of the objects can be selected at any one time. So if we checked the female object then the male object would become unchecked and vice-versa. We set the male HtmlRadioButton to be selected initially. We do this calling the generic method setBooleanAttribute(name,on) and setting the "checked" attribute to be on. All HtmlRadioButton objects require a value. The value of each object must be unique amongst a group of HtmlRadioButtons, otherwise the objects will not be able to correctly identify the checked object.
m_txaStreet = new HtmlTextArea(m_tblLayout.getTableCell(5, 1), "m_txaStreet");
m_txaStreet.setCols("40");
m_txaStreet.setRows("3");
The object we create in this code is the HtmlTextArea object. The object is similar to the HtmlTextBox object in that it allows users to enter textual data. It differs in that this object can provide multiple lines to the user to type in, as oppose to the HtmlTextBox object which only provides one line. Here we set a HtmlTextArea object with 40 columns and 3 rows.
m_cbxPostalAddress = new HtmlCheckBox(m_tblLayout.getTableCell(9, 1), "m_cbxPostalAddress");
m_cbxPostalAddress.setValue("Y");
Here we create a HtmlCheckBox object. The HtmlCheckBox allows a user to either check an option as on or off. A HtmlCheckBox must have a value set, otherwise the object will not be able to correctly identify if the object has been checked by the user.
m_tblLayout.getTableRow(12).setBgColor("#D7FFFF");
The above line of code sets the background color of a table row. Here the row at the 12th index position will have the specified background color (sets the "bgcolor" attribute). A reference to a HtmlTableRow object can be obtained by calling the getTableRow(row) method.
m_tblLayout.getTableCell(12, 0).setColSpan(2);
m_tblLayout.getTableCell(12, 0).setAlign("center");
We can set the "colspan" attribute of a HtmlTableCell with the setColSpan(size) method. Notice that unlike most other wrapper methods, the argument type here is not a String but an integer. This is so because the value is actually used internally by HtmlTable to work out which table cells are visible and which are not. By spanning the column size of a HtmlTableCell, this will effectively increase the visible space of the table cell and will result in the HtmlTableCell overlapping neighbouring HtmlTableCell objects. In this case, by spanning across 2 cells the HtmlTableCell at (12,0) will also occupy the space of the HtmlTableCell at (12,1). The HtmlTableCell at (12,1) becomes hidden, setVisible(false) is actually called on this cell as it has been spanned over. We also set the "align" attribute of the table cell at (12,0) to "center". This means that all children objects of this cell will be aligned in the center of the cell.
m_btnSave = new HtmlPushButton(m_tblLayout.getTableCell(12, 0), "m_btnSave");
m_btnSave.setText("Save");
m_btnSave.setButtonType("submit");
m_btnReset = new HtmlPushButton(m_tblLayout.getTableCell(12, 0), "m_btnReset");
m_btnReset.setText("Reset");
m_btnReset.setButtonType("reset");
This bit of code here creates 2 HtmlPushButton objects. A HtmlPushButton object provides the user with a clickable component that generally triggers off a specific action. The first button that we create is a save button that allows the user to save the form details. The second button created is a reset button that can be used by the user to reset the form to its original values. The button-type of a HtmlPushButton gives it different action properties. There are generally 3 button-types that are used, "submit", "reset" and "button". A "submit" HtmlPushButton when clicked will cause the form data to be posted to the target of the form. A "reset" HtmlPushButton will reset the form data back to the original values of the form when the form was loaded. The last type "button" which is not used here, doesn't trigger off any action by default. It is normally used to trigger client scripting code (i.e. Javascript).
private boolean validateForm()
Now that we've pretty much covered most of the code in the constructor method we will move onto the next method in our class. This method validateForm() will be used to validate whether our CustomerForm has been correctly completed by the user. Our example if relatively simple, all that is required for the form to be valid is that the 4 mandatory fields are completed, Title, First Name, Last Name and Email address.
boolean bValid = true;
if (m_selTitle.isSelected(0) == true)
{
bValid = false;
m_tblLayout.getTableCell(0, 0).setClassAttribute("error");
}
The first object we check is the title object. This is a HtmlListBox object, the only option that is not valid is the first one. So we check whether the first option is selected by using the isSelected(index) method. If the option is selected then we flag the form as invalid. We also set the "class" attribute for the corresponding table cell to the "error" style-sheet class because we want to highlight which fields are incomplete to the user. When the form is redrawn the "Title *" label will be highlighted in a red color.
if (m_txtFirstName.getText().trim().length() == 0)
{
bValid = false;
m_tblLayout.getTableCell(1, 0).setClassAttribute("error");
}
We do the same validation for all the other fields. For the HtmlTextBox object we can extract the form data by using the getText() method.
if (bValid == false)
{
m_htmUserMessage.setText("Please fill in the mandatory fields highlighted below.");
m_parUserMessage.setVisible(true);
m_parUserMessage.setClassAttribute("error");
}
Now that we've gone through each of the mandatory fields, we check to see whether the form is valid or not. If the form is not valid then what we want to do is display a message to the users. We set our message in our HtmlText object m_htmUserMessage. If you recall earlier this object is contained inside the HtmlParagraph object m_parUserMessage which was set to be invisible. So to make this message visible we need to make the parent object m_parUserMessage visible. Calling setVisible(visible) on a HtmlContainerWidget object will also call the setVisible(visible) method on all its children. We set the style-sheet class of the HtmlParagraph object to be "error" so our message will also be displayed in a red color.
public void saveForm()
This public method should be called when the form details are to be saved to the database (or some other permanent storage). The method will first validate the form, if the form is validate then it will proceed to save the details to the database and will show a confirmation message. The code for saving the data to the database has been omitted as this is not relevant to the tutorial.
m_tblLayout.setAttribute("class", null, true);
m_tblLayout.setAttribute("class", "normal");
The first thing we want to do when saving the form is to clear any highlighted field labels. If you recall, the validateForm() method highlighted incomplete fields by setting the "class" attribute of the HtmlTableCell objects to the "error" style-sheet class. Now it may be the case that the form was previously invalid and the user has now completed the mandatory fields and has clicked save again. So what we must do it make sure all the "class" attributes of the relevant objects are cleared. We could do this by going through each HtmlTableCell object one by one. But there is an easy way, we can call the overloaded version of setAttribute(name,text,all) provided by the HtmlContainerWidget class. This version will set the specified attribute for itself and for all of the objects children if the last boolean parameter is set to true. In our above code, we clear the "class" attribute for the HtmlTable object and all of its children by passing the null reference for the value. The next line sets the "class" attribute back to the "normal" style-sheet class.
if (validateForm())
{
m_htmUserMessage.setText("Your customer details have been saved.");
m_parUserMessage.setVisible(true);
m_parUserMessage.setClassAttribute("info");
}
If the form is validate then will display a user message indicating the details have been saved (we have not included the code to save to the database for simplicity sake). We do this by setting the text in the m_htmUserMessage object and by making the m_parUserMessage object visible.
customer.jsp
if (request.getParameter("m_btnSave") == null)
The first we need to do is identify whether this is the first time we are loading the form or if we are loading the form from a post submission. A way we can do this is to check what parameters are in the request object. If we have submitted the form then one of the parameters that will exist is the m_btnSave parameter. This parameter comes from the 'Save' HtmlPushButton.
CustomerForm objForm = new CustomerForm();
objForm.printHtml(out);
request.getSession().setAttribute("customerform", objForm);
We've identified that the form has not been loaded yet, so we create a new instance of the CustomerForm class. In the next line we call the method printHtml(output), which writes out the html that represents the form. The method loops through all the HtmlWidget objects contained in the form and calls printHtml(output) on those objects as well. There are 2 version of the printHtml(output) method, one takes in a JspWriter object and the other takes in a PrintWriter, these are for Jsp pages and Servlets respectively. In the last line we save the form in the session object. We do this so we can reference the form when the user makes a post submission.
CustomerForm objForm = (CustomerForm)request.getSession().getAttribute("customerform");
If we identify that form has been submitted back to the server then we need retrieve our form so we can work on it. We retrieve our the form object back from the session object.
objForm.updateData(request);
The updateData(request) method is a very important method in the toolkit. The method will iterate through all the HtmlControlWidget objects contained in the form and will update the state of each object depending on the posted parameters contained in the request object. Each HtmlControlWidget object has their own implementation of updateData(request) but the general result is to update its internal state to represent what was posted from the user. In our example, all the customer fields that the user posted are magically updated in our form. So say the user entered "John" into the first name field, then after calling this method the m_txtFirstName object will contain the data "John". This makes handling form data much more intuitive and makes your code much more like what you'll do in Java-Swing.
objForm.saveForm();
objForm.printHtml(out);
Here we simply call our previously defined saveForm() method. One we have saved our form, we are ready to write out the current form state to the client.
Conclusion
Ok we're done! That was a lot of code and a lot of concepts, but hopefully this gives you a good idea on how you can program with Objective Html and the benefits it can bring to your project. If anyone picks up mistakes in this tutorial please let me know.
Be sure to check out the next tutorial: Using Objective Html and Struts
Also check out the tutorial on how to separate page design and logic: Separating Page Design and Logic