Are you building applications that generate dynamic data, then using XSL to transform that data into HTML or some other client interpretable language? If so, you might want to spice up the presentation and user-interface by throwing some JavaScript into the mix. Unfortunately though, it is not always easy to create such a mix.
Let us assume a piece of your application generates a listing of all the fields that define a document type. The list includes three columns:
- Name of the field
- HTML Select Box to edit the Data Type for the field
- HTML Select Box to edit the Control Type for the field
Here is some typical XML that your application components might generate:
<?xml version="1.0" encoding="UTF-8"?>
<doctype>
<field id="123">
<datatype>1</datatype>
<controltype>7</controltype>
<name>Movie Poster</name>
</field>
<field id="456">
<datatype>1</datatype>
<controltype>1</controltype>
<name>Director</name>
</field>
<field id="789">
<datatype>1</datatype>
<controltype>3</controltype>
<name>Movie Rating</name>
</field>
</doctype>
And here is the XSL to generate a very basic HTML table from this data:
<xsl:template match="/">
<table>
<xsl:apply-templates select="doctype/field">
<xsl:sort select="name"/>
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="field">
<tr fieldID="{@id}">
<td>
<xsl:value-of select="name"/>
</td>
<td>
<xsl:value-of select="datatype"/>
</td>
<td>
<xsl:value-of select="controltype"/>
</td>
</tr>
</xsl:template>
The resulting HTML would be as follows:
<table>
<tr fieldID="123">
<td>Movie Poster</td>
<td>2</td>
<td>7</td>
</tr>
<tr fieldID="456">
<td>Director</td>
<td>2</td>
<td>1</td>
</tr>
<tr fieldID="789">
<td>Movie Rating</td>
<td>2</td>
<td>3</td>
</tr>
</table>
Aside from the actual field names, this data is pretty much meaningless. In fact, the second and third columns, Data Type and Control Type respectively, have no meaning whatsoever to the user. The ideal solution would be to replace the number in those columns with a Select Box and have the correct item selected. That means you will need some way to generate select boxes with different items selected n times.
Add this JavaScript to the XSL:
/**
* function writeTypes()
* Parameters:
* whichSel = Which data type to select
* 1 for String
* 2 for Numeric
* 3 for Date
*/
// Variable to be used as unique ID for each "data type" select box generated
var whichType = 1;
function writeTypes(whichSel) {
var html = "<select id='data" + whichType + "'>";
switch (whichSel) {
case '1':
html += "<option value='string' SELECTED='true'>String</option>";
html += "<option value='numeric'>Numeric</option>";
html += "<option value='date'>Date</option>";
break;
case '2':
html += "<option value='string'>String</option>";
html += "<option value='numeric' SELECTED='true'>Numeric</option>";
html += "<option value='date'>Date</option>";
break;
case '3':
html += "<option value='string'>String</option>";
html += "<option value='numeric'>Numeric</option>";
html += "<option value='date' SELECTED='true'>Date</option>";
break;
}
html += "</select>";
whichType++;
document.write(html);
}
/**
* function writeControlTypes()
* Parameters:
* whichSel - Which control type to select
* - 1 for Textfield
* - 2 for Checkbox
* - 3 for Select Box
* - 4 for Textarea
* - 5 for Radio Button
* - 6 for Password
* - 7 for File Upload
*/
// Variable to be used as unique ID for each "control type" select box
// generated.
var whichControlType = 1;
function writeControlTypes(whichSel,sendString,newField) {
var html = "<select id='cntrl" + whichControlType + "'>";
switch (whichSel) {
case '1':
html += "<option value='textfield' SELECTED='true'>Textfield</option>";
html += "<option value='checkbox'>Checkbox</option>";
html += "<option value='selectbox'>Select Box</option>";
html += "<option value='textarea'>Textarea</option>";
html += "<option value='radiobutton'>Radio Button</option>";
html += "<option value='password'>Password</option>";
html += "<option value='file'>File</option>";
break;
case '2':
html += "<option value='textfield'>Textfield</option>";
html += "<option value='checkbox' SELECTED='true'>Checkbox</option>";
html += "<option value='selectbox'>Select Box</option>";
html += "<option value='textarea'>Textarea</option>";
html += "<option value='radiobutton'>Radio Button</option>";
html += "<option value='password'>Password</option>";
html += "<option value='file'>File</option>";
break;
case '3':
html += "<option value='textfield'>Textfield</option>";
html += "<option value='checkbox'>Checkbox</option>";
html += "<option value='selectbox' SELECTED='true'>Select Box</option>";
html += "<option value='textarea'>Textarea</option>";
html += "<option value='radiobutton'>Radio Button</option>";
html += "<option value='password'>Password</option>";
html += "<option value='file'>File</option>";
break;
case '4':
html += "<option value='textfield'>Textfield</option>";
html += "<option value='checkbox'>Checkbox</option>";
html += "<option value='selectbox'>Select Box</option>";
html += "<option value='textarea' SELECTED='true'>Textarea</option>";
html += "<option value='radiobutton'>Radio Button</option>";
html += "<option value='password'>Password</option>";
html += "<option value='file'>File</option>";
break;
case '5':
html += "<option value='textfield'>Textfield</option>";
html += "<option value='checkbox'>Checkbox</option>";
html += "<option value='selectbox'>Select Box</option>";
html += "<option value='textarea'>Textarea</option>";
html += "<option value='radiobutton' SELECTED='true'>Radio Button</option>";
html += "<option value='password'>Password</option>";
html += "<option value='file'>File</option>";
break;
case '6':
html += "<option value='textfield'>Textfield</option>";
html += "<option value='checkbox'>Checkbox</option>";
html += "<option value='selectbox'>Select Box</option>";
html += "<option value='textarea'>Textarea</option>";
html += "<option value='radiobutton'>Radio Button</option>";
html += "<option value='password' SELECTED='true'>Password</option>";
html += "<option value='file'>File</option>";
break;
case '7':
html += "<option value='textfield'>Textfield</option>";
html += "<option value='checkbox'>Checkbox</option>";
html += "<option value='selectbox'>Select Box</option>";
html += "<option value='textarea'>Textarea</option>";
html += "<option value='radiobutton'>Radio Button</option>";
html += "<option value='password'>Password</option>";
html += "<option value='file' SELECTED='true'>File</option>";
break;
}
html += "</select>";
whichControlType++;
document.write(html);
}
If you ran this, you would find a few errors and realize nothing is really happening. The problem is that the XML is being transformed before there is any concept of the JavaScript, so all of the <SELECT> and <OPTION> tags are being rendered as HTML before the JavaScript is executed. As far as the transformation process is concerned, the JavaScript is just more HTML. But you need the tags to not be rendered until the functions are called, so the XSL needs to be told to ignore any would-be tags that are generated in the JavaScript.
One way to do this is to replace all the tag-starting < characters with the ASCII equivalent, <. Each of the <OPTION> lines in the JavaScript would now look something like this:
html += "<option value='file'>File</option>";
Now, when the transformation process happens, each < is seen and turned into a <. The end result is an HTML tag in a JavaScript string that will not be rendered until the functions are called.
The same method applies for using the "less than" operator in JavaScript. If you write JavaScript code like this in your XSL:
if (var1 < var2) {
// Code here
}
you will have a problem because the transformation will think the < is the beginning of an HTML tag. In this case also, you would need to write this:
if (var1 < var2) {
// Code here
}
The last step in this process is to call the appropriate JavaScript methods from the XSL to generate the Select Boxes. Here is the field XSL template to use with the JavaScript:
<xsl:template match="field">
<tr fieldID="{@id}">
<td>
<xsl:value-of select="name"/>
</td>
<td>
<script>writeTypes('<xsl:value-of select="datatype"/>');</script>
</td>
<td>
<script>writeControlTypes('<xsl:value-of select="controltype"/>');</script>
</td>
</tr>
</xsl:template>
Now, your final output will have Select Boxes in the second and third columns and the correct option will already be selected.
|