The XForms switch, case and toggle elements are often used to implement a tabbed view in complex applications. This article demonstrates how they can also be employed at a much finer granularity to build individual composite controls.
This approach can be of particular use when the available display area is severely limited, as the following code shows:
<xf:switch> <xf:case id="case-display"> <xf:trigger> <xf:label ref="/data" /> <xf:action ev:event="DOMActivate"> <xf:toggle case="case-edit" /> <xf:setfocus control="edit" /> </xf:action> </xf:trigger> </xf:case> <xf:case id="case-edit"> <xf:input ref="/data" id="edit"> <xf:toggle ev:event="DOMFocusOut" case="case-display" /> </xf:input> </xf:case> </xf:switch>
Another scenario where composite controls can be helpful is when a trigger is used to invoke some activity that may take a long time to complete. In these cases, a busy animation can be switched for the activated trigger, indicating to the user that the application is processing their request:
<xf:switch> <xf:case id="case-ready"> <xf:trigger> <xf:label>Submit</xf:label> <xf:action ev:event="DOMActivate"> <xf:toggle case="case-busy" /> ... </xf:action> </xf:trigger> </xf:case> <xf:case id="case-busy"> <img src="status-busy.gif" alt="Please wait..." /> </xf:case> </xf:switch>
toggle back to the ready case. 
JavaScript composite control
JavaScript composite control version:
HTML (this is the only bit your designer would have to change - the rest is automagic):
<span onclick="edit()" data="location.of.data">text to in-line edit</span>
In addition you would need to add the following site wide JavaScript (only once though). There is some Mootools syntax, but could be rewritten for raw JS:
// Adds in-line edit to any span/div and places the data
// at the location defined in the element's 'data' property
function edit(event) {
var field = event.currentTarget;
eval('var prop = ' + field.get('data'));
// Create the editable element and add a closure that does the updates
var input = new Element('input').addEvent('change',function() {
swapInElement(field, input);
prop = input.get('value'); field.set('text',prop);
// You may want to add a global update function here
});
swapInElement(input, field).focus();
}
One utility function for completeness sake...
function swapInElement = function(toAdd,toRemove) {
var previousNode = toRemove.getPrevious();
var parent = toRemove.getParent();
toRemove.dispose();
if (!$defined(previousNode)) {
toAdd.inject(parent, 'top');
} else {
toAdd.injectAfter(previousNode);
}
return toAdd;
}