Define a custom tag for table display and make your Web applications easier to manage. You'll reduce the overhead of writing the same piece of code multiple times because you update the code in only one place. The Tag class reflects your changes across all JSP pages. Here, I'll explain how to create a custom tag for table display that is flexible enough to handle different HTML controls, such as href, checkbox, radio button, text field, and combo box.
Custom tags are user-defined JSP language elements. When a JSP page that contains a custom tag translates into a servlet, the tag converts to operations (doStartTag() and doEndTag()) on an object, called a tag handler. The Web container then invokes those operations when the JSP's servlet executes.
Custom tags have a rich set of features. They can:
- Access all the objects available to JSP pages.
- Modify the response that the calling page generates.
- Communicate with each other. You can create and initialize a JavaBeans component, create a variable that refers to that bean in one tag, and then use the bean in another tag.
You can also:
- Customize the tags through attributes passed from the calling page
- Nest them within one another, allowing for complex interactions within a JSP page
Some advantages of custom tags are:
- Page designers can abstract from a complex set of logic. While the JSP page that references the tag executes, the JSP runtime invokes the tag handler class to execute the business logic it defines.
- You can use a custom tag on multiple places simply by invoking the tag, and remove the repetition of writing the same piece of code in different places.
- For any future code changes, you just make the change in one place; in the
Tagclass, which reflects the changes across all applicable JSP pages.
Suppose that the application development of a mutual fund system requires over 100 JSP pages, and most of the pages need table data. However, not all JSP pages require the same type of table data. In that case, you want to design a custom tag that supports all these table types.
When you design the table tag, users should be able to specify the following:
- Width of a table column
- Link (href) for a table column
- Checkbox or radio button as column values
- How values align (left/right)
- Text fields (for user input)
- Combo box as column data
- Navigation for table data (Prev/Next)
You will use the jspTableID key to uniquely identify the table tag entries for a particular JSP page. You can define any value but make sure it uniquely identifies the particular table.
Table tag uses two property files -- TableHeaderDisplay.properties and TableValueDisplay.properties -- to specify table header values and data values.
TableHeaderDisplay.properties defines the column header names, column width, and control names for the jspTableID key. This is the sample property entry in TableHeaderDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = Employee No:150:href&First Name:210&Last Name:150 &Dept:150&Job:60 |
SearchEmployee.jsp&EmployeeSearchResultsis thejspTableID.Employee No,First Name,Last Name,Dept, andJobare the column header names.150,210,150,150, and60are corresponding column widths.- The href for column
Employee Nospecifies a link to the Employee No. column.
TableValueDisplay.properties defines the value objects to the jspTableID key. This is the sample property entry in TableValueDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = EmployeeSearchResults@com.ibm.optimistic.model.bo.Employee@EmpNo &FirstName&LastName&Dept&Job |
SearchEmployee.jsp&EmployeeSearchResultsis thejspTableID.EmployeeSearchResultsis the session attribute name, where the rows of records are stored for table display.com.ibm.optimistic.model.bo.Employeeis the value object to hold data for each row.EmpNo&FirstName&LastName&Dept&Jobare the variable names defined in the value object.
The following code for a JSP page invokes the table tag to display the Employee table (single line of code displayed on multiple lines for viewing convenience):
<tblTag:tableBuilder jspTableID="SearchEmployee.jsp&EmployeeSearchResults"> </tblTag:tableBuilder> |
Define a tld file for the table tag
A tld file defines one tag called tableBuilder. The table tag's core logic is defined in the com.ibm.optimistic.tags.TableTag class. The tag has one mandatory attribute: jspTableID. You must use this attribute to identify the table uniquely.
The tag has two optional attributes: paginate and formName. The paginate attribute determines whether or not pagination is required. If paginate equals true, the table displays the Prev/Next buttons. You use the formName attribute to set the name of the form that contains a table. The attribute takes the default value as forms[0].
Listing 1. Define a tableBuilder tag
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>customtags</shortname>
<uri>/WEB-INF/taglib.tld</uri>
<tag>
<name>tableBuilder</name>
<tagclass>com.ibm.optimistic.tags.TableTag</tagclass>
<attribute>
<name>jspTableID</name>
<required>true</required>
</attribute>
<attribute>
<name>paginate</name>
<required>false</required>
</attribute>
<attribute>
<name>formName</name>
<required>false</required>
</attribute>
</tag>
</taglib> |
As I mentioned, we will define the table tag's core logic in the TableTag class. To implement this class, you first create the JspWriter object to send the HTML content to the browser.
javax.servlet.jsp.JspWriter obj_JspWriterOutToBrowser = null; obj_JspWriterOutToBrowser = pageContext.getOut(); |
The following code block:
- Gets the
Localeobject. - Reads the property files
TableHeaderDisplay.propertiesandTableValueDisplay.properties. - Reads the header and value entries, based on the
jspTableID. - Obtains the reference for the table ID, value object class, session attribute for data rows, and session attribute for combo box if one exists.
- Parses the property entry and stores it in a hashtable for future reference.
Listing 2. Define core logic in TableTag class
/** Assigning the default lang */
obj_LocaleGetDefault = Locale.getDefault();
/** loading the TableHeaderDisplay properties file*/
obj_ResourceBundleHeaderProperty = ResourceBundle.getBundle(
HEADER_PROPFILE,obj_LocaleGetDefault);
StringTokenizer obj_StringTokenizerTableKey =
new StringTokenizer(sJspTableID,"&");
obj_StringTokenizerTableKey.nextToken();
String sTableID = obj_StringTokenizerTableKey.nextToken();
/** loading the TableValueDisplay properties file*/
obj_ResourceBundleValueProperty = ResourceBundle.getBundle(
VALUE_PROPFILE,obj_LocaleGetDefault);
/**
Reading the Header property by passing its respective key
as an attribute
*/
String sGetColumnHeader =
obj_ResourceBundleHeaderProperty.getString(sJspTableID);
/**
Reading the TableValue property by passing its respective key
as an attribute
*/
String sGetVOClassName =
obj_ResourceBundleValueProperty.getString(sJspTableID);
/** passing the TableValue property as an argument */
StringTokenizer obj_StringTokenizer =
new StringTokenizer(sGetVOClassName,"@");
/** get the vector attribute from the tokenizer and assign it
to string
*/
String sSessionAttribute = obj_StringTokenizer.nextToken();
/** get the ValueObject name from the tokenizer and assign it
to string
*/
String sValueObject= obj_StringTokenizer.nextToken();
/**
get all method names as single token from the tokenizer
and assign it to string
*/
String sValueObjectMethods= obj_StringTokenizer.nextToken();
String sComboAttrib = new String(" ");
Hashtable obj_HashtableColumnHeader = new Hashtable();
StringTokenizer obj_StringTokenizerColumnValue =
new StringTokenizer(sGetColumnHeader,"&");
int iColumnNumber =0;
char[] cCSS = new char[obj_StringTokenizerColumnValue.countTokens()];
for (iColumnNumber = 1;
obj_StringTokenizerColumnValue.hasMoreTokens();iColumnNumber++) {
StringTokenizer obj_StringTokenizerColumnSubValue = null;
obj_StringTokenizerColumnSubValue = new StringTokenizer
(obj_StringTokenizerColumnValue.nextToken(),":");
for(int iParaNumber =
1;obj_StringTokenizerColumnSubValue.hasMoreTokens();iParaNumber++) {
String sHtKey = "col" + iColumnNumber + "N" + iParaNumber;
String sHtString = obj_StringTokenizerColumnSubValue.nextToken();
if(sHtString != null) {
if(sHtString.equalsIgnoreCase("combo")) {
StringTokenizer sCombo =
new StringTokenizer(sSessionAttribute,":");
sSessionAttribute = sCombo.nextToken();
sComboAttrib = sCombo.nextToken();
}
}
obj_HashtableColumnHeader.put(sHtKey,sHtString);
} // END OF INNER FOR LOOP
} // END OF OUTER FOR LOOP |
If the attribute bPaginate is true, then the table displays the Prev/Next buttons.
if(bPaginate==true){
obj_JspWriterOutToBrowser.println("<input type ='button' class =
'BUTTON' "+ "name ='Prev' value='Previous'
onclick=setTableTagMode('Prev')>");
obj_JspWriterOutToBrowser.println("<input type ='button' class =
'BUTTON' "+ "name ='Next' value='Next'
onclick=setTableTagMode('Next')>");
obj_JspWriterOutToBrowser.println("<br>");
} |
To create the HTML tag for table display, use:
obj_JspWriterOutToBrowser.println("<table border='1' cellpadding='0' "+
"width=\"750\" cellspacing='0' name='"+sTableID+"'
id='"+sTableID+"'>"); |
The code in Listing 3 creates the table header. It parses the table header property entry, gets the column name details, and aligns the flag (left/right) for displaying the table data.
Listing 3. Create the table header
obj_JspWriterOutToBrowser.println("<tr>");
StringTokenizer obj_StringTokenizerColumnHeader =
new StringTokenizer(sGetColumnHeader,"&");
obj_ArrayListAlignFlag = new java.util.ArrayList(
obj_StringTokenizerColumnHeader.countTokens());
while (obj_StringTokenizerColumnHeader.hasMoreTokens()) {
String sColumnToken = obj_StringTokenizerColumnHeader.nextToken();
StringTokenizer sColumnSubToken =
new StringTokenizer(sColumnToken,":");
while (sColumnSubToken.hasMoreTokens()) {
String sColumnHeader = sColumnSubToken.nextToken();
StringTokenizer sColumnSub =
new StringTokenizer(sColumnHeader," ");
StringBuffer sColumnHead = new StringBuffer();
String sTemp;
while (sColumnSub.hasMoreTokens()) {
sTemp = sColumnSub.nextToken();
if(sTemp.equalsIgnoreCase("<r>"))
{
sAlignFlag="r";
}
else
{
sColumnHead.append(sTemp);
sColumnHead.append(" ");
}
}
String sWidthSize = sColumnSubToken.nextToken();
if(sAlignFlag.equalsIgnoreCase("r"))
{
obj_ArrayListAlignFlag.add("r");
}
else
{
obj_ArrayListAlignFlag.add("l");
}
iNoCols++;
/****** displays Table Column Headers *****/
obj_JspWriterOutToBrowser.println("<td "+
"class='columnLabelString' "+
"height='20' width="+sWidthSize +
" align='center' nowrap>"+
sColumnHead.toString()+"</td>");
break;
}
}
obj_JspWriterOutToBrowser.println("</tr>"); |
Next, you get the session reference, and then retrieve the table data (vector of value objects) and combo box data (vector of strings) from the session.
/** gets HttpSession object from pageContext */
javax.servlet.http.HttpSession obj_HttpSessionVecOfValueObject =
pageContext.getSession();
/** Retrieves vector of value objects from session */
obj_VectorValueObject =
(Vector)obj_HttpSessionVecOfValueObject.getAttribute(sSessionAttribute);
/** Retrieves vector of strings from session */
Vector obj_VectorObject = (Vector)
obj_HttpSessionVecOfValueObject.getAttribute(sComboAttrib); |
To calculate startRecord and endRecord to be displayed on the page, you:
- Load the
ValueObjectclass. - Check for pagination. If pagination is enabled, then calculate the starting value based on the Prev/Next mode the user selects.
- For the Next button,
StartValue = startValuefromSession+Numberof records per page. LoopCounterholds the last record to be displayed on the page.- For nonpagination display,
startValue = 0, andLoopCounterequals the size of the vector holding the table data.
In Listing 4, you can see how it works:
Next, you retrieve the values from the value object and store them in a vector.
- The tag handler class iterates on the vector of value objects. For each value object, the values are stored in the inner vector. The outer vector holds all the inner vector objects.
- Using the Reflection API, you obtain each variable's value and store it in the inner vector.
Listing 5. Retrieve values from the value object and store them in a vector
/* outer for loop starts */
for (int i = 0; i < obj_VectorValueObject.size(); i++) {
/** gets the valueobject from the vector */
Object obj_ObjectVO = obj_VectorValueObject.elementAt(i);
/**
passing the getter methods as an argument
to the StringTokenizer constructor
*/
StringTokenizer obj_StringTokenizerVOMethods =
new StringTokenizer(sValueObjectMethods, "&");
/** This String object gets the value from the value object */
String sMethodValue = null;
Vector obj_VectorInnerVector = new Vector();
/* inner for loop starts */
for (int k = 0;
obj_StringTokenizerVOMethods.hasMoreTokens();
k++) {
String sFieldName =
obj_StringTokenizerVOMethods.nextToken().trim();
/**
check the field names, if field name is not a control,
invoke the method;
otherwise, add a dummy string to the inner vector
*/
if (!sFieldName.equals("control")) {
/**
Get the VO field names from the TableValueDisplay
property file and pass it as an argument to getMethod()of class
object, which returns the java.lang.reflect.Method object
*/
Method obj_MethodDynamic =
obj_ClassDynamic.getMethod("get" + sFieldName, null);
cCSS[k] = sFieldName.charAt(0);
/**
the getter methods are called dynamically using
the invoke method of java.lang.reflect.Method object
*/
Object obj_ObjectVOValue =
(obj_MethodDynamic.invoke(obj_ObjectVO, null));
/**
if obj_ObjectVOValue is null, then assign a namespace value
to the string object; otherwise, convert the object value
to string and assign it to sMethodValue variable
*/
if (obj_ObjectVOValue == null
|| (obj_ObjectVOValue.toString()).trim().equals(""))
sMethodValue = " ";
else
sMethodValue = obj_ObjectVOValue.toString();
} //end for control check
/**
if the field is a control, add a dummy string
to the inner vector
*/
if (obj_HashtableColumnHeader.get("col" + (k + 1) + "N" + 3)
!= null) {
if (!(obj_HashtableColumnHeader
.get("col" + (k + 1) + "N" + 3)
.equals("href"))) {
/** TextBox starts */
if (sFieldName.equals("control")) {
obj_VectorInnerVector.addElement("");
} else {
obj_VectorInnerVector.addElement(sMethodValue);
}
} else {
obj_VectorInnerVector.addElement(sMethodValue);
}
} else {
obj_VectorInnerVector.addElement(sMethodValue);
}
} // inner for loop ends
/** vector, which contains values to be displayed
in the table, is added into another vector for simplicity */
obj_VectorOuterVector.addElement(obj_VectorInnerVector);
} // end of outer for loop |
Then you print this JavaScript function at client side to handle the radio button.
Listing 6. JavaScript function for radio button
obj_JspWriterOutToBrowser.println("<script language='JavaScript'>");
obj_JspWriterOutToBrowser.println(
"function " + "handleTableRadioCtrl(linkIndex) {");
if (bFlag)
obj_JspWriterOutToBrowser.println(
"document." + sFormName
+ ".iTableLink.value = linkIndex;}");
else
obj_JspWriterOutToBrowser.println(
"document.forms["
+ iFormNumber
+ "].iTableLink.value = linkIndex;}");
obj_JspWriterOutToBrowser.println("</script>"); |
Next, print this JavaScript function at client side to handle the hyperlink.
Listing 7. JavaScript function for hyperlink
obj_JspWriterOutToBrowser.println("<script language='JavaScript'>");
obj_JspWriterOutToBrowser.println(
"function " + "handleTableLink(linkIndex) {");
if (bFlag) {
obj_JspWriterOutToBrowser.println(
"document." + sFormName + ".iTableLink.value = linkIndex");
obj_JspWriterOutToBrowser.println(
"document." + sFormName + ".jspMode.value = 'Link'");
obj_JspWriterOutToBrowser.println(
"document." + sFormName + ".submit()}");
} else {
obj_JspWriterOutToBrowser.println(
"document.forms["
+ iFormNumber
+ "].iTableLink.value = linkIndex");
obj_JspWriterOutToBrowser.println(
"document.forms["
+ iFormNumber
+ "].jspMode.value = 'Link'");
obj_JspWriterOutToBrowser.println(
"document.forms[" + iFormNumber + "].submit()}");
}
obj_JspWriterOutToBrowser.println("</script>"); |
The table column value starts processing here. The code iterates on the outer vector; for each inner vector, it creates a <tr> element. While constructing <tr>, the code performs different checkups for different controls.
Listing 8. Process the table column value
if (obj_VectorOuterVector.size() != 0) {
for (int iNoOfRows = iStartValue;
iNoOfRows < iLoopCounter;
iNoOfRows++) {
Vector obj_VectorOneRowValue =
(Vector) obj_VectorOuterVector.elementAt(iNoOfRows);
/*******Table Row Value Starts****************/
obj_JspWriterOutToBrowser.println("<tr>");
for (int iColumn = 0;
(iColumn < obj_VectorOneRowValue.size());
iColumn++) {
if !(obj_HashtableColumnHeader
.get("col" + (iColumn + 1 "N" + 3) == null)) {
String strColumnType =
(String) obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 3);
}
} |
To create a textbox as your table column:
Listing 9. Create a textbox as the table column
if ((strColumnType.toLowerCase()).startsWith("textbox")) {
sMaxLength = "20";
if (strColumnType.trim().length() > 7) {
sMaxLength =
strColumnType.substring(7, strColumnType.trim().length());
}
String textFiledSizeIE = "";
String textFiledSizeNS = "";
try {
textFiledSizeIE =
"" + ((new Integer(sMaxLength).intValue()) + 1);
if ((new Integer(textFiledSizeIE).intValue()) > 7) {
textFiledSizeNS =
"" + ((new Integer(textFiledSizeIE).intValue()) / 2);
} else {
textFiledSizeNS = textFiledSizeIE;
}
} catch (NumberFormatException obj_NumberFormatException) {
textFiledSizeIE = "20";
textFiledSizeNS = "10";
}
obj_JspWriterOutToBrowser.println(
"<td height=\"15\" align=\"center\" width=\"40\">"
+ "<script>\n if(document.layers) \n "
+ " document.write(\" "
+ "<input class='formBox' type=text size="
+ textFiledSizeNS
+ " maxlength='"
+ sMaxLength
+ "' value='"
+ obj_VectorOneRowValue.elementAt(iColumn)
+ "' name="
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4)
+ ">\"); \n"
+ " else \n "
+ " document.write(\" "
+ "<input class='formBox' type=text size="
+ textFiledSizeIE
+ " maxlength='"
+ sMaxLength
+ "' value='"
+ obj_VectorOneRowValue.elementAt(iColumn)
+ "' name="
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4)
+ ">\"); \n"
+ "</script> "
+ "</td>");
} |
Alternatively, to create a checkbox as your table column:
Listing 10. Create a check box as the table column
/** for CheckBox **/
if (strColumnType.equalsIgnoreCase("CheckBox")) {
chkField =
(String) obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4);
obj_JspWriterOutToBrowser.println(
"<td height=\"15\" align=\"center\" "
+ " nowrap>"
+ "<input tabindex='2' "
+ " type=checkbox "
+ " name="
+ chkField.trim()
+ " onClick=\"javascript:chkStatus"
+ "(this.form."
+ (chkField.trim())
+ iChkElementCount
+ ".value,this.checked)\">"
+ "<input type=hidden name="
+ chkField.trim()
+ iChkElementCount
+ " value="
+ iChkElementCount++
+ " >"
+ " </td>");
obj_JspWriterOutToBrowser.println(
"<input type=hidden name=hd"
+ chkField.trim()
+ " value='off'>");
} |
To create a radio button as your table column:
Listing 11. Create a radio button as the table column
if (strColumnType.equalsIgnoreCase("Radio")) {
obj_JspWriterOutToBrowser.println(
"<td class=radioButton "
+ "height=\"15\" align=\"center\" >"
+ " <input type=radio name="
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4)
+ " onClick=javascript:handleTableRadioCtrl('"
+ ilinkIncrement++
+ "')></td>");
iRadioButtonIncrement++;
} |
To create a button as your table column:
Listing 12. Create a button as the table column
if (strColumnType.equalsIgnoreCase("Button")) {
obj_JspWriterOutToBrowser.println(
"<td width=\"63\" "
+ "height=\"15\" align=\"center\" width=\"50\">"
+ " <input type=button name="
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4)
+ " value = "
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 5)
+ " onClick=javascript:handleTableButtonCtrl('"
+ iButtonIncrement++
+ "')></td>");
} |
To create a combo box as your table column:
Listing 13. Create a combo box as the table column
if (strColumnType.equalsIgnoreCase("Combo")) {
StringTokenizer obj_StringTokenizerCombo = null;
obj_JspWriterOutToBrowser.println(
"<td width=\"50\" "
+ " align=\"center\" height=\"24\"><select "
+ " class=ListString name="
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4)
+ " id="
+ obj_HashtableColumnHeader.get(
"col" + (iColumn + 1) + "N" + 4)
+ ">");
for (int i = 0; i < obj_VectorObject.size(); i++) {
obj_StringTokenizerCombo =
new StringTokenizer(
(String) obj_VectorObject.elementAt(i),
"&");
String sComboValue = obj_StringTokenizerCombo.nextToken();
String sComboValueFromVec =
(String) obj_VectorOneRowValue.elementAt(iColumn);
String sComboDisplay =
obj_StringTokenizerCombo.nextToken();
if (sComboValue
.trim()
.equalsIgnoreCase(sComboValueFromVec.trim())
|| sComboDisplay.trim().equalsIgnoreCase(
sComboValueFromVec.trim())) {
obj_JspWriterOutToBrowser.println(
"<option value="
+ sComboValue
+ " selected>"
+ sComboDisplay
+ "</option>");
} else {
obj_JspWriterOutToBrowser.println(
"<option "
+ "value="
+ sComboValue
+ ">"
+ sComboDisplay
+ "</option>");
}
}
obj_JspWriterOutToBrowser.println("</select></td>");
} |
Finally, to create an href link as your table column:
Listing 14. Create an href link as the table column
if (strColumnType.equalsIgnoreCase("href")) {
String sHrefLink =
(String) obj_VectorOneRowValue.elementAt(iColumn);
obj_JspWriterOutToBrowser.println(
"<td tabindex='1' align=\"center\" class=link height=\"15\" "
+ ilinkIncrement++
+ "')>"
+ sHrefLink
+ "</a></td>");
} |
The tag handler class prints this JavaScript function at client side to handle checkbox values:
Listing 15. JavaScript function to handle checkbox values
if (chkField != null) {
if (bFlag) {
obj_JspWriterOutToBrowser.println(
"<script language=javascript> ");
obj_JspWriterOutToBrowser.println(
"document.body.onunload=deselect;");
obj_JspWriterOutToBrowser.print("var ichkElementLength=");
obj_JspWriterOutToBrowser.print(
"document."
+ sFormName.trim()
+ "."
+ chkField.trim()
+ ".length;\n");
obj_JspWriterOutToBrowser.println(
"function deselect()\n{\nfor(i=0;i<ichkElementLength;i++)\n");
obj_JspWriterOutToBrowser.println(
"{ \n if(document."
+ sFormName.trim()
"."
+ chkField.trim()
+ "[i].checked)");
obj_JspWriterOutToBrowser.println(
"{\ndocument."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ "[i].value='on';}}}");
obj_JspWriterOutToBrowser.println(
" function chkStatus(val,bool)\n");
obj_JspWriterOutToBrowser.println(
"{\n if(!document.layers) \n if(document."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ ".length)");
obj_JspWriterOutToBrowser.print(
"\n{\ndocument."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ "[val].");
obj_JspWriterOutToBrowser.print(
"value= bool ?'on':'off';\n}\nelse\n{\n");
obj_JspWriterOutToBrowser.print(
"document."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ ".value=");
obj_JspWriterOutToBrowser.print("bool ?'on':'off';\n}\n ");
obj_JspWriterOutToBrowser.println(
"\n if(document.layers) \n if((\"\"+document."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ ").indexOf(\"object InputArray\") != -1 ) ");
obj_JspWriterOutToBrowser.print(
"\n{\ndocument."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ "[val].");
obj_JspWriterOutToBrowser.print(
"value= bool ?'on':'off';\n}\nelse\n{\n");
obj_JspWriterOutToBrowser.print(
"document."
+ sFormName.trim()
+ ".hd"
+ chkField.trim()
+ ".value= bool ?'on':'off';");
obj_JspWriterOutToBrowser.print("} } \n</script>\n");
} else {
obj_JspWriterOutToBrowser.println(
"<script language=javascript>\n ");
obj_JspWriterOutToBrowser.println(
"document.body.onunload=deselect;");
obj_JspWriterOutToBrowser.print("var ichkElementLength=");
obj_JspWriterOutToBrowser.print(
"document.forms["
+ iFormNumber
+ "]."
+ chkField.trim()
+ ".length;\n");
obj_JspWriterOutToBrowser.print(
"function deselect()\n{\nfor(i=0;i<ichkElementLength;i++)\n");
obj_JspWriterOutToBrowser.print(
"{\n if(document.forms["
+ iFormNumber
+ "]."
+ chkField.trim()
+ "[i].checked)\n");
obj_JspWriterOutToBrowser.print(
"{\ndocument.forms["
+ iFormNumber
+ "].hd"
+ chkField.trim()
+ "[i].value='on';}}}");
obj_JspWriterOutToBrowser.print(
" function chkStatus(val,bool)\n");
obj_JspWriterOutToBrowser.print(
"{\nif(document.forms["
+ iFormNumber
+ "].hd"
+ chkField.trim()
+ ".length)\n");
obj_JspWriterOutToBrowser.print(
"{\ndocument.forms["
+ iFormNumber
+ "].hd"
+ chkField.trim()
+ "[val].");
obj_JspWriterOutToBrowser.print(
"value= bool ?'on':'off';\n}\nelse\n{\n");
obj_JspWriterOutToBrowser.print(
"document.forms["
+ iFormNumber
+ "].hd"
+ chkField.trim()
+ ".value=");
obj_JspWriterOutToBrowser.print(
"bool ?'on':'off';\n}\n}\n</script>");
}
} |
The tag handler prints this JavaScript function at client side to handle the Previous and Next buttons.
Listing 16. JavaScript function to handle Previous and Next buttons
if (bPaginate == true) {
obj_JspWriterOutToBrowser.println("<script language='JavaScript'>");
obj_JspWriterOutToBrowser.println(
"function setTableTagMode(sMode){");
if (iStartValue == 0) {
obj_JspWriterOutToBrowser.println("if(sMode=='Prev'){");
obj_JspWriterOutToBrowser.println(
"alert('There are no previous records');");
obj_JspWriterOutToBrowser.println("return;}");
}
if (iLoopCounter >= obj_VectorOuterVector.size()) {
obj_JspWriterOutToBrowser.println("if(sMode=='Next'){");
obj_JspWriterOutToBrowser.println(
"alert('There are no more records');");
obj_JspWriterOutToBrowser.println("return;}");
}
if (bFlag) {
obj_JspWriterOutToBrowser.println(
"document." + sFormName + ".jspMode.value = sMode");
obj_JspWriterOutToBrowser.println(
"document." + sFormName + ".submit();}");
} else {
obj_JspWriterOutToBrowser.println(
"document.forms["
+ iFormNumber
+ "].jspMode.value = sMode");
obj_JspWriterOutToBrowser.println(
"document.forms[" + iFormNumber + "].submit();}");
}
obj_JspWriterOutToBrowser.println("</script>");
} |
Sample screen captures for a table
Note: In your JSP page, include the hidden parameter jspMode to set the action name. The request processing class must set the action name to the jspMode session variable so the table tag can use it to track user actions.
<input type="hidden" name="jspMode" > |
The request processing class also must set the session variable jspMode with the parameter value read from the request object.
if (request.getParameter("jspMode") != null){
request.getSession().setAttribute("jspMode",
request.getParameter("jspMode"));
} |
To create a simple table display for viewing search results, use the following property files:
TableHeaderDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = Employee No:150&First Name:210&Last Name:150&Dept:150&Job:60 |
TableValueDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = EmployeeSearchResults@com.ibm.optimistic.model.bo.Employee@EmpNo &FirstName&LastName&Dept&Job |
Figure 1 illustrates this view.
Figure 1. Search results
To create a table display with href as the column type, use these property files:
TableHeaderDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = Employee No:150:href&First Name:210&Last Name:150 &Dept:150&Job:60 |
TableValueDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = EmployeeSearchResults@com.ibm.optimistic.model.bo.Employee@EmpNo &FirstName&LastName&Dept&Job |
When you display a table with an href column (see Figure 2), the HeaderDisplay property contains the Employee No:150:href entry to set a link to the Employee No. column.
The user clicks the href link to call the following JavaScript function:
<script language='JavaScript'>
function handleTableLink(linkIndex) {
document.forms[0].iTableLink.value = linkIndex
document.forms[0].jspMode.value = 'Link'
document.forms[0].submit()}
</script> |
For Employee No:111111, handleTableLink(0) calls the above function. The function sets the form variable iTableLink with an index of the selected href link, and the jspMode identifies the user action, such as save, update, or delete. To get the details of the corresponding href, use the iTableLink value. The iTableLink represents the index of the value object. (The table data comes from the session; it is stored in the session with the vector of value objects).
Figure 2. Table with href column
To create a table display with a checkbox as the column type, use the following property files.
TableHeaderDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = Employee No:150&First Name:210&Last Name:150 &Dept:150&Job:60&Delete:20:checkbox:chkDelete |
TableValueDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = EmployeeSearchResults@com.ibm.optimistic.model.bo.Employee@EmpNo &FirstName&LastName&Dept&Job&control |
The HeaderDisplay property contains the Delete:20:checkbox:chkDeleteentry to display the checkbox.
The user clicks the checkbox to call the following JavaScript function. The function sets the hdchkDelete to On or Off, depending on whether a user selects or deselects a checkbox.
function chkStatus(val,bool) {
if(document.forms[0].hdchkDelete.length){
document.forms[0].hdchkDelete[val].value= bool ?'on':'off';
}else{
document.forms[0].hdchkDelete.value=bool ?'on':'off';
}
} |
Figure 3 displays a table with checkboxes. A user can select any number of records and delete an operation. The request handling class reads the parameter values for hdchkDelete. It deletes the record if the corresponding checkbox has the value of On.
You can read the selected checkbox index values from the request object String[] values = request.getParameterValues("hdchkDelete");.
Figure 3. Table with checkbox column
To create a table display with radio buttons (see Figure 4) as the column type, you will use these property files:
TableHeaderDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = Select:50:radio:rdInclude &Employee No:150&First Name:210&Last Name:150 &Dept:150&Job:60 |
TableValueDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = EmployeeSearchResults@com.ibm.optimistic.model.bo.Employee@control &EmpNo&FirstName&LastName&Dept&Job |
The HeaderDisplay property contains the Select:50:radio:rdInclude entry to display the radio buttons.
The user clicks on a radio button to call the following JavaScript function.
function handleTableRadioCtrl(linkIndex) {
document.forms[0].iTableLink.value = linkIndex;
} |
For Employee No:111111, handleTableRadioCtrl ('0') calls the above function. The function sets the form variable iTableLink with the selected radio button's index. To get the corresponding record's details, use the iTableLink value. The iTableLink represents the value object's index. (The table data comes from the session; it is stored in the session with the vector of value objects).
You can read the selected radio button index from the request object: String selectedIndex = request.getParameter("iTableLink");.
Figure 4. Table with radio button as column
To create a table display with a textbox/combo box as the column type (see Figure 5), use these property files:
TableHeaderDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = Employee No:150&First Name:150:textbox:FirstName&Last Name:150:textbox:LastName &Dept:150:textbox:Dept&Job:60:textbox:Job&Sex:80:combo:sex |
TableValueDisplay.properties (single line of code displayed on multiple lines for viewing convenience):
SearchEmployee.jsp&EmployeeSearchResults = EmployeeSearchResults:Sex@com.ibm.optimistic.model.bo.Employee@EmpNo &control&control&control&control&control |
The HeaderDisplay property contains the following entries to display the textbox and combo box:
First Name:150:textbox:FirstNamefor the textbox entrySex:80:combo:sexfor the combo box entry
The TableValueDisplay.properties file contains the session attribute key (Sex) for the combo box after the table data session attribute key (EmployeeSearchResults).
The request processing class reads the parameter values from the request as follows:
FirstNameValues [0], FirstNameValues [1]... to read firstName values
LastNameValues [0], LastNameValues [1]... to read lastName values
String[]FirstNameValues = request.getParameterValues("FirstName");
String[]LastNameValues = request.getParameterValues("LastName"); |
Figure 5. Table with textbox/combo box as the column
In this article, you learned how to create a custom tag for table data display with different html controls, including href, checkbox, radio button, text field, and combo box. For complex applications with many JSP pages, you reduce your coding and maintenance efforts with this table tag.
| Description | Name | Size | Download method |
|---|---|---|---|
| The zip file contains TableTag related files | wa-custmtag_source.zip | 47 KB | HTTP |
Information about download methods
Learn
- "Take Control of Your JSP Pages with Custom Tags" explains how custom tags communicate with each other, and how you can combine them to increase reusability and flexibility (developerWorks, January 2002).
- Find detailed information about tag libraries in the JavaServer Pages Standard Tag Library.
- Visit the developerWorks Web Architecture zone. It specializes in articles covering various Web-based solutions.
Discuss
- Get involved in the developerWorks community by participating in developerWorks blogs.





