Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

The Secret Life of XForms : Page 4

XForms recently reached the W3C's Candidate Recommendation status—and you need to know about it—because XForms isn't a form description language, it's a language for describing applications in a platform-independent way. Best of all, it integrates easily with technologies you already know, such as XHTML, XPath, SVG, and CSS.


advertisement
Binding it Together
Some of you may have begun to visualize the letters MVC floating in the background—not as some 1940s Roman epic movie (or 1990s remake) but as the initials for Model/View/Controller. In the early 1970s, the language Smalltalk introduced this particular design architecture. Simply put, the MVC architecture supposes you have a discrete model containing, some kind of output view, and then code of some sort to bind the view to the model—a controller that handled event input and the mappings between the two.

XForms is very nearly a pure embodiment of MVC. The distinction between model and view (or user interface) is fairly clean. The binding mechanism, though, can seem a little confusing at first, because XForms actually relies on a few different effects to handle the binding.

At the very lowest level, you have the ref attribute, which tells the XForm engine to associate a particular element or attribute value in the model with the control. For instance, in the Cost Per Share section of the example form, you have the output tag:

<xforms:output ref="format-number( /stockData/account/stock/value, '$#,##0.00')">

The ref attribute contains an XPath expression, usually pointing to one or more elements within the model. In the above case, the XPath expression uses the stock value as retrieved from the XPath expression /stockData/account/stock/value. XForms passes the retrieved value to the XPath function format-number, which converts the price into a string of the form '$#,##0.00', a number mask indicating that the string should include the US dollar symbol, with a separator at the thousands point (Continental readers would of course use a different mask).

In this particular case the reference in the ref attribute is read only. However, references can go both ways. For instance, the sample XForm also inserts the initial value of the /stockData/account/shares element into the Number of Shares input box item.

<xforms:input ref="/stockData/account/shares"/>

When users change this field, nothing happens until they press the button (trigger) marked "Calculate".



<xforms:trigger> <xforms:label>Calculate</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref= "/stockData/account/totalCost" value="format-number( number(/stockData/account/shares) * number(/stockData/account/stock/value), '##0.00')"/> </xforms:action> </xforms:trigger>

The <action> element is XForms' closest approximation to a subroutine. Actions take their context based upon the elements that called them (or the elements that they are in), and the specific event. For instance, a trigger invokes a "DOMActivate" event when pressed (activated), causing any and all internal DOMActivate actions contained within to run. It is possible, though not recommended, to have multiple event handlers with the same event key.

The <setvalue> command uses the ref attribute to retrieve an element or attribute from the model, then replaces the current value of the reference with the evaluated XPath expression in the value attribute. In this particular instance, the form takes the number of shares entered by the user, and multiplies that by the currently selected stock's value. Finally, it formats and displays the result as a floating point number with two significant displayed digits.

The selection box is more complex:

<xforms:select1 ref= "/stockData/account/stock/symbol"> <xforms:action ev:event="xforms-value-changed"> <xforms:setvalue ref= "/stockData/account/stock/name" value="/stockData/stocks/stock[symbol = /stockData/account/stock/symbol]/name"/> <xforms:setvalue ref= "/stockData/account/stock/value" value="/stockData/stocks/stock[symbol = /stockData/account/stock/symbol]/value"/> <xforms:setvalue ref= "/stockData/account/totalCost" value="format-number( (/stockData/account/shares) * (/stockData/account/stock/value), '##0.00')"/> </xforms:action> <xforms:itemset nodeset= "/stockData/stocks/stock"> <xforms:label ref="name"/> <xforms:value ref="symbol"/> </xforms:itemset> </xforms:select1>

When the user makes a selection, XForms invokes the event xforms-value-changed on the selection box, which then invokes the three <setvalue> statements, changing the symbol, the stock value, and the total cost based upon this price and the number of outstanding shares. Changing the values automatically notifies all interface elements bound to them so they can update their own content, thus the <output> elements change their displayed values automatically.

This may seem like a lot of work for what should be a fairly simple application, but there are some real advantages. Handling cascading values, where changing one control causes other controls to change their internal contents—their models—as well, is notoriously difficult. But in this case, the XForms engine acts as the notifier, handling all the uglier notification processes, and leaving developers free to concentrate on establishing the data paths and other resources. This has the advantage of making the code easier to maintain as well.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap