Personal tools
You are here: Home Products PloneFormGen Documentation How-Tos Installing a JavaScript Event Handler in a Form
Document Actions

Installing a JavaScript Event Handler in a Form

This How-to applies to: Any version.

This how-to presents an example of using a PloneFormGen form override to enable a dynamic totalling function in an order form.

This how-to is really more of a code example than a how-to. It shows the python script I used in a form to handle two dynamic functions:

  1. Update an on-screen total whenever a new selection was made from any multiple-selection widget on the form;
  2. Make a multi-selection widget act more like a radio button widget by turning off all the other options whenever an option is checked. (The mutiple-selection widget was being displayed as a list of check boxes.)
Be warned. The code isn't going to make sense if you don't know JavaScript and Python. It's presented to demonstrate some techniques rather than as a recipe.
The basics of the form are that it had several multiple-selection widgets, each displayed as a list of check boxes. The options of each multiple-selection widget were meant to be mutually exclusive. Each option also had a price as the last text in text in the label (e.g., "choose me to pay $50").

The code below was installed as a python script, then called from the Header Injection field of the form folder's [overrides] panel.

It has two major parts:

  1. It constructs the JavaScript text for two arrays; one connects prices with ids, the other is a list of lists of mutually exclusive ids.
  2. It returns a big chunk of prewritten JavaScript into which the price and exclude arrays are interpolated. As a bonus, it also includes a little bit of CSS to style the presentation of the dynamically totalled price.
The JavaScript makes use of one item from Plone's JavaScript library: it calls registerPloneFunction to register a function for execution when the page is displayed. This solves the  chicken-and-egg problem of how to use code in an XHTML header to work on elements in the body.

And, let me add that I regard this script as basically a hack. It isn't meant to demonstrate good coding form; it just solves a single problem. It's meant to be read for the techniques it uses, not reproduced in your application.

The Script

# get our list of fields from the form folder
fields = context.fgFields()

# iterate the fields, looking for MultiSelectionWidgets
pitems = []
for field in fields:
if field.getWidgetName() == 'MultiSelectionWidget':
# get all the values of the field; extract their prices
# throw them into pitems in the format of an element of a
# JavaScript array
fname = field.getName()
count = 1
for flab in field.Vocabulary(context).values():
try:
price = flab[flab.rindex('$')+1:]
except:
price = '0'
pitems.append( "['%s_%d', %s]" % (fname, count, price) )
count += 1
prices = ',\n'.join(pitems)

pitems = []
for field in fields:
if field.getWidgetName() == 'MultiSelectionWidget':
fname = field.getName()
flen = len(field.Vocabulary(context))
for idx in range(1, flen+1):
current = '%s_%d' % (fname, idx)
exc = ['%s_%d' % (fname, idy) for idy in range(1, flen+1)]
exc.remove(current)
pitems.append( "'%s' : %s" % (current, exc) )
excludes = ',\n'.join(pitems)


return \
"""
<script type="text/javascript">

var sform = {}

sform.priceArray = [%s];

sform.excludes = {%s};

sform.docalc = function(e) {
var total=0;
var i, j;
var item, nitem;
var toExclude;
var elem;

// get element from event
if (e) {
elem = e.target;
} else {
// IE compatibility
var e = window.event;
if (e) {
elem = e.srcElement;
}
}

// do excludes
if (elem && elem.checked) {
elemid = elem.id;
var exs = sform.excludes[elemid];
if (exs) {
for (i=0; i < exs.length; i++) {
document.getElementById(exs[i]).checked = false;
}
}
}

// do totals
for (i=0; i < sform.priceArray.length; i++) {
item = document.getElementById(sform.priceArray[i][0]);
if (item.checked) {
total += sform.priceArray[i][1];
}
}

// update the displayed total
document.getElementById('gtotal').innerHTML = '$'+total;
}

// create a function that will install our click handler
// and do the first update
sform.symf_setup = function() {
var eid, item;

for (var i=0; i < sform.priceArray.length; i++) {
eid = sform.priceArray[i][0];
item = document.getElementById(eid);
item.onclick = sform.docalc;
}
sform.docalc();
}

// register our function to run on page display
registerPloneFunction(sform.symf_setup);
</script>


<!-- inject some CSS as well -->
<style>
#gtotal_table {
width: 100%%;
border-bottom: 1px solid black;
margin-bottom: 1em;
}
#gtotal_table th {
font-weight: bold;
font-size: large;
text-align: left;
}
#gtotal_table td {
text-align: right;
text-decoration: overline;
font-weight: bold;
font-size: large;
}
</style>

""" % (prices, excludes)

by Steve McMahon last modified May 8, 2007 - 18:19

For any issues with the web site functionality, please file a ticket.

Please consult the policy on plone.org content if you want your content published on this site.

Servers and hosting by