XForms/Table Column Total
Motivation
Frequently a form must display the total of a column. This can be accomplished using the bind function in the model.
Sample Program
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xf="http://www.w3.org/2002/xforms" > <head> <style type="text/css"> @namespace xf url("http://www.w3.org/2002/xforms"); * { font-family: Ariel, Helvetica, sans-serif } .table-header, .table-footer { display: table-row; } .column-header, .column-footer { display: table-cell; text-align: center; color: white; background-color: gray; font-weight: bold; } /* make the "Total:" in the table footer right align */ .table-footer .item-description, .table-footer .item-amount { text-align: right; } .item-description { width: 300px; } .item-amount { width: 112px; } .item-description .xf-value { width: 300px; text-align: left } .item-amount .xf-value { width: 100px; text-align: right } </style> <title>Demonstration of table with column total</title> <xf:model id="my-model"> <xf:instance id="my-data" src="my-data.xml" xmlns=""/> <xf:bind nodeset="/Data/Total" calculate="sum(../Item/Amount)"/> <xf:submission id="update-from-local-file" method="get" action="my-data.xml" replace="instance" instance="my-crv"/> <xf:submission id="view-xml-instance" method="get" action="my-data.xml"/> <xf:submission id="save-to-local-file" method="put" action="my-data.xml"/> </xf:model> </head> <body> <div class="table-header"> <div class="column-header item-description">Description</div> <div class="column-header item-amount">Value</div> </div> <xf:group ref="/Data"> <!-- For each Person in the PersonList display the name and phone--> <xf:repeat nodeset="Item" id="repeatItem"> <xf:input id="description-input" ref="Description" class="item-description"/> <xf:input ref="Amount" class="item-amount"/> <br /> </xf:repeat> <div class="table-footer"> <div class="column-footer item-description">Total:</div> <div class="column-footer item-amount"> <xf:output ref="/Data/Total" /> </div> </div> <xf:trigger id="insertbutton"> <xf:label>Add Item</xf:label> <xf:action ev:event="DOMActivate"> <xf:insert nodeset="Item[last()]" position="after" at="last()"/> <xf:setvalue ref="Item[last()]/Description" value="''"/> <xf:setvalue ref="Item[last()]/Amount" value="0"/> <!-- put the cursor in the name field --> <xf:setfocus control="description-input"/> </xf:action> </xf:trigger> <xf:trigger id="delete"> <xf:label>Delete Item</xf:label> <xf:delete nodeset="Item[index('repeatItem')]" at="index('repeatItem')" ev:event="DOMActivate"/> </xf:trigger> <br /> <xf:submit submission="update-from-local-file"> <xf:label>Reload</xf:label> </xf:submit> <xf:submit submission="save-to-local-file"> <xf:label>Save</xf:label> </xf:submit> <xf:submit submission="view-xml-instance"> <xf:label>View XML Instance</xf:label> </xf:submit> </xf:group> </body> </html>
Sample my-data.xml instance file
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Item>
<Description>Furniture</Description>
<Amount>1000</Amount>
</Item>
<Item>
<Description>Dock</Description>
<Amount>2000</Amount>
</Item>
<Item>
<Description>Boat</Description>
<Amount>3000</Amount>
</Item>
<Item>
<Description>Lawn equipment</Description>
<Amount>4000</Amount>
</Item>
<Item>
<Description>Hot tub</Description>
<Amount>5000</Amount>
</Item>
<Total>15000</Total>
</Data>
Discussion
This example uses div blocks for the table header and footer. The total will be updated each time the user tabs out of a field. New items are always added to the end but you can delete an existing item just by selecting it and pressing the "Delete item" button.
