XForms/Print version

From Wikibooks, open books for an open world
< XForms
Jump to: navigation, search


XForms

The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
http://en.wikibooks.org/wiki/XForms

Permission is granted to copy, distribute, and/or modify this document under the terms of the Creative Commons Attribution-ShareAlike 3.0 License.


Contents

Guest Registry

We would like to know who is using this cookbook. Please tell us all little about yourself:

Template Organization-Name[edit]

  • Contact Name:
  • Organization:
  • Location:
  • Use: How are you using the book?
  • Like: What did you like the most about the XForms Tutorial and Cookbook? What samples were the most useful?
  • Improve: What would you like to see improved in the book? What new examples would you like?

County Community College[edit]

  • Name: County Community College
  • Location: New Jersey
  • Use: Teaching yourself, teaching others, college classroom, high school etc.
  • Like:

I am looking for a working examples that my students could use to build their own XForms applications. I will be using the example in this book to help my students learn about XForms.

US Federal Agency[edit]

  • Name: Federal Agancy
  • Location: Washington DC
  • Use: Teaching our staff how to build XRX applications and manage TEI documents
  • Like: Working progams
  • Improve: More sample document workflow application

Minnesota Department of Revenue - Property Tax Division[edit]

  • Name: Dan McCreary
  • Location: St. Paul Minnesota
  • Use: We are using the cookbook to learn XForms and build property taxation form.
  • Like: We like XForms because we can generate them from XML Schemas and we don't need any Java or C# or VB to when we use the eXist native XML database
  • Would Like: We would like more examples that use XML Binding (XBL)

A Financial Institution[edit]

  • Location: Minneapolis Minnesota
  • Use: We use the cookbook to teach internal staff how to build an maintain forms
  • Like: Small working examples. The links are great.
  • Would Like: Examples of process management forms and Schematron rules engines using XForms

ZheJiang, China[edit]

  • Name: zhouliyi
  • Location: ZheJiang,China
  • Use: We are using the cookbook to share XForms examples and document our best practices.
  • Like: XForms is great for creating prototypes of our forms.
  • Would like: How you create XForms by transforming a source XML Schema information would be very nice.
  • Example: Examples that integrate with databases would be great.

NIC - Open Technology Centre[edit]

  • Contact Name: Rajamani M
  • Organization: NIC - Open Technology Centre
  • Location: India
  • Use: We are using the cookbook to share XForms , XRX examples and

developing sample applications.

  • Like: We like the XRX sample with Database connected
  • Improve: More examples to expand the concept in each element and functions

Drybridge Consulting[edit]

  • Contact Name: Arthur Colman
  • Organization: Drybridge Consulting
  • Location: Boston, MA USA
  • Use: Using the cookbook to upgrade our implementation of XForms and to share examples.
  • Like: The broad range of examples.

Xerox[edit]

  • Contact Name: Jacob Woodworth
  • Organization: Xerox
  • Location: Rochester, NY
  • Use: Implementation using XForms.
  • Like: The examples I've seen here are the best I've found on the Web.
  • Improve: TBD

Grant Solutions[edit]

  • Organization: Grant Solutions
  • Location: Rockville Maryland
  • Use: Teaching developers and BAs to use XForms (Orbeon)
  • Like: Beginning guides
  • Improve: more materials on binds and submission

Send us a Postcard![edit]

If you really like the book please send a postcard to:

Dan McCreary
3007 Cavell Ave. So
St. Louis Park, MN 55426

It would be very much appreciated!



Naming Conventions

Here are some naming conventions used for this WikiBook. These naming conventions are designed to be consistent across the sample programs, allowing our students to be able to copy and paste blocks of code from the sample programs with a minimum amount of reformatting. So even though it may be a little bit annoying to have the xf: prefix on the XForms data elements, it does make it easy for students to quickly build new applications from the samples.

The audiences for much of this material are state and federal agencies that are converting paper forms to electronic forms. As a result we tend to use the XML Naming and Design Guidelines used by these organizations. Since these standards are built around ISO/IEC-11179 and other ebXML standards, they should not be too strange to most business developers.

There are over 150 of "Naming and Design Rule" guidelines but we don't need to use them all. A web site that discusses them is the Component Organization and Registration Environment web site.

Here are some guide lines to start out with:

Indentation[edit]

Please use three space characters to indent your examples. MediaWiki does not allow us to set tab stops and by default they are 8 characters.

Wrap XML Code in Source Tags[edit]

Please enclose all your sample XML code with the source tags with the lang="xml" attribute like this:

<source lang="xml">
 ....your XML code here...
</source>

Namespace Standards[edit]

Namespaces are core to XForms today and essential for our examples to work under a large number of diverse platforms. Please take some time to think carefully about namespaces and namespace prefixes.

Please use the following template at the head of your example:

<html 
   xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
   ...

Note that the first line:

xmlns="http://www.w3.org/1999/xhtml" 

indicates that the file uses XHTML as its default namespace. Any tags that do not have a namespace prefix are by default elements in the xhtml namespace.

We feel that keeping the examples in this default namespace will make students familiar with HTML more at home with XForms. Standard tags such as <h1>, <p>, <b> and <i> can be freely used in all our examples.

You can optionally add the XML processing instruction before the <html> tag:

<?xml version="1.0" encoding="UTF-8"?>

but most XForms systems do not need this. Any file that has a file extension of ".xhtml" implicitly implies that it is an XML file.

Warnings about DOCTYPE[edit]

Please do not put the !DOCTYPE tag in the header for xhtml1-strict.dtd. This specifically states that the file ONLY contains XHTML and most systems will not allow XForms tags when they see this. Many example programs have this and it should be removed to be correct.

XForms Player Specific Markup[edit]

Please do not put any player-specific markup in the examples. This book is about W3C standards, specifically XForms, CSS, XML Schema and XHTML. These examples should not require a specific implementation of a client forms player. If you are working with a specific player that does require special HTML tags, they can be automatically inserted by the web application server using an XML transform. This allows these examples to be used in a wide variety of classroom environments and by a large number of server and client XForms players.

For a general template see XForms/Template

For player specific instructions see Player Specific Instructions.

List of Example Program Naming Conventions[edit]

  1. Use a separate namespace for HTML, XForms controls and Data.
  2. Give HTML the default namespace. This makes it easy to take existing XHTML code and use it in the examples
    1. If it is not possible to give HTML a default namespace, give it a namespace prefix that is short, such as "h".
  3. Use the "xf" namespace prefix for XForm elements. I find about 3/4 of the examples use this already but some use the full "xform" or "xforms" prefix. I suggest avoiding the confusion and just use "xf" since it is short and in common use already.

Examples for US State and Federal Agencies[edit]

It is our hope that many US state and federal agencies may integrate this material into their training programs. This is an important audience for XForms since much of the XForms standards were promoted by agencies that did not allow JavaScript to be executed on their desktops for security reasons.

The namespace that we are using for most of our federal data model examples is the NIEM. The namespace prefix is "u" for "Universal" data elements for things like Address, Contact, Activity, Documents, Organizations, Person. The NIEM also has a very nice sub-schema generator that works very well with the process of building forms. See the niem.gov web site for more information on this. If you have any suggestions on any better tools then the NIEM tools, please let us know.

Next Page: Comparison of XForms Products | Previous Page: Installing and Testing

Home: XForms



Examples Wanted

Here are some examples were are still looking for:

Examples Wanted[edit]

Here is list of the example progams we are looking for in rough order of priority (highest priority examples are first)

  1. Example to format currency - We would like an example that formats based on numeric picture formats such as "$#,###.##".
  2. Validate Field by Character Set - We would like to validate a field base on a pattern character set. So for example we would like to mark a field invalid if it has special characters such as non-alpha or non-numerics. How do you specify this in a binding rule? Can you bind it to an XML Schema data type?
  3. Full CRUD Example on dynamic file Demonstrate the full create, read, update delete (CRUD) cycle for some form data selected from a file local file system. The example load the form data from a file (use the upload control) into an instance document and (similar to using the src="" attribute), view the data, edit the data and save the data back to a file using a submit to a file. For doing this on a static file see Read and write with get and put
  4. Display required elements from Schema - A XML Schema file can tell you exactly what fields are required (if the minOccurs is not zero). Demonstrate how these fields can be automatically be displayed using CSS and the :required pseudo element
  5. Instance validation - An example based on an external XML schema. Validate an instance using the XML Schema file. Validate
  6. XMLEvents Demonstrate how XML Events work with event propagation. Show how events bubble up the event responder tree.
  7. Use industry standard forms (IRS tax forms, ACORD insurance forms etc).
  8. A XForms example incorporating XML Signing in XHTML preferably with digital filters too.
  9. Full CRUD Example using any Database Demonstrate the full create, read, update delete (CRUD) cycle for some form data selected from a database. The example load the form data from a database into an instance document and (similar to using the src="" attribute), view the data, edit the data and save the data back to a database using a submit

Non FireFox Examples[edit]

FireFox does not have Pseudo_element_support for ::value, ::repeat-item, and ::repeat-index. See Pseudo element support in FireFox Are their any other systems that will support this that we can get examples from?

Finished Examples[edit]

  1. Get information from an XHTML web page - use the instance src to extract a value from an XHTML file. See Read and write with get and put
  2. Web Service Examples using REST - Examples of calling a web service using the simplified REST protocol where web service arguments are just passed in a URL. See XForms/Search flickr and XForms/Search Amazon
  3. Call a web service from a form using the submit command. We would like an example that does not require the students to register to use a web service. See Web service
  4. XForms/Load from XML Schema - Load an XML Schema and use the data types in the XML Schema to validate data types in a form.
  5. Facet Validation - We would like to have a family of example programs that validate based on the facets of an XML Schema file but it appears that the FireFox extension does not yet support facet validation (restrictions based on length, minLength, maxLength, etc) so this is somewhat difficult to demonstrate easily in a classroom setting when the students are just running the FireFox browser.
  6. Set textarea size. Use the CSS to set the area of a textarea size differently of many boxes. See Textarea with style



Introduction

Introduction to XForms

XForms is a standardized set of HTML form elements, designed to be integrated with other world-wide-web standards.

XForms has many advantages over traditional HTML web forms that use complex JavaScript. These advantages include:

  1. an elegant Model-View-Controller (MVC) architecture
  2. a movement toward declarative programming which is easier to learn, maintain and debug
  3. a rich set of user interface controls for handling complex things such as dates, numbers and ranges
  4. compatibility with XML standards such as Cascading Style Sheets (CSS), XML Schema and XPath
  5. extensibility

XForms can be run today from almost any web browser by either using an downloadable plugin or extension (such as the Firefox extension) or by loading a JavaScript file. For more information see the Benefits section of this book.

About this book[edit]

This book is intended to be a tutorial and cookbook with many complete running XForms examples. The initial examples are designed to teach the fundamental concepts of XForms. The more advanced examples are designed to solve specific tasks and reduce the amount of JavaScript necessary to write high-quality forms.

We would like to have the examples ordered from simple to complex. At the end of the cookbook there are integration examples of how to extend and integrate XForms with other systems such as web services.

The philosophy behind this book centers around the fact that people often learn best by taking a fully-functioning program and making slight modifications to it to understand how it works.

Guidelines for contributors[edit]

Please feel free to add your own examples to this tutorial and cookbook! Here are a few suggestions for contributors:

Focus on Tutorial Examples[edit]

The first set of examples should focus on new XForms users. Please keep tutorials on foundational concepts (XPath and XML Schema) in a separate area so that users already familiar with these concepts can skip these sections.

Focus on Reducing JavaScript[edit]

One of the goals of this book is to help forms developers move away from hard-to-maintain scripting languages such as JavaScript. Any examples that focus on getting rid of commonly used JavaScript functions are very much appreciated.

Testing[edit]

Please tell us what XForms systems you have used to test your examples. If you can, we recommend testing using the major browsers (Internet Explorer and Firefox) using either an extension, plug-in or a JavaScript translator such as FormFaces. See also the Installing XForms in Firefox.

We would like to eventually have a small box in the upper right corner that tells what systems each example was tested under.

Avoid Duplication[edit]

Try to avoid duplication with other example programs in this cookbook and other Wikibooks on CSS, XML Schemas and XPath. That being said, sometimes the cookbook needs small samples of CSS and XPath to demonstrate how they are integrated with XForms.

Naming Conventions[edit]

Our first goal is to get as many complete working examples installed for new users of XForms. After they are working, they should hopefully be made as consistent as possible. This document describes an initial attempt at some of the naming conventions used in previous examples.

Next Page: Background

Home: XForms



Background

Background[edit]

The XForms standard arose from the desire of many people to use the web for more than just linking documents. The original design of the world wide web standard introduced many innovative concepts including the URL, the HTML markup language and the HTTP protocol.

But innovation aside, elegant form processing was not one of the design goals of the initial HTML language. In fact, many of the advanced input fields were added to the HTML specification after it became popular.

One thing is clear: the introduction of clean MVC concepts were never part of the original HTML specification. Many attempts were made to introduce better controls into browsers and the HTML language, but most of these additions fell short for four reasons:

  1. They were either browser or vendor specific solutions to a specific problem
  2. They did not integrate mainstream developments in XML Schema, XPath and CSS
  3. They did not take into account the need for clear separation-of-concerns
  4. They did not meet the rigorous needs of application architects that understood the benefits of MVC architectures

As a result, many of these point-solutions have been discarded or have seen only niche use by some vendors.

Around 1997 the W3C started to address the concerns of these users and studied how web forms could be processed in a better way. They realized that validating data elements was a large concern and that re-inventing the validation tools already present in XML Schema would only duplicate efforts.

The first XForms draft specification was published on April 6, 2000. Since then it has been revised with the most recent version (1.1) appearing in March of 2006.

Today the XForms standard addresses several web forms development issues:

  1. Model-View-Binding architecture
  2. Advanced functionality
  3. Precise specification for all browsers to integrate
  4. Extensibility without resorting to JavaScript programming
  5. Built-in assumptions about how form elements get updated

The Dependency Graph[edit]

Embedded within every XForms application is the ability to automatically recalculate values when a form element changes. If you have a complex form with calculation rules then this feature becomes critical for avoiding writing manual recalculation code. Most JavaScript forms libraries require the author to specify not only form rules, the order these rules must be executed. This slow and painful form-author-specified recalculation order is replaced in XForms by an automated method to determine the order of recalculation.

The way XForms applications do this is by doing automated determination of recalculation order based on optimal graph algorithms.

One of the most important papers about how XForms is designed come from the following paper:

The XForms Computation Engine: Rationale, Theory and Implementation Experience html version

If you have a simple form with just a few elements and no calculation rules, HTML forms might be a good solution for you. If you have forms with rules such as sum and total calculations in a purchase order, then XForms might be the ideal fit for your web form.

For the current working draft of the XForms specification you can go to the w3 web site:

W3C Candidate Recommendation 29 November 2007

Next Page: Benefits | Previous Page: Introduction

Home: XForms



Benefits

Why XForms?[edit]

There are many benefits to using XForms over traditional HTML forms. Some of the most frequently mentioned benefits are:

Benefits of XForms[edit]

  1. Web Standard - XForms is a W3C standard and allows web applications to be created without lockin to any specific vendor such as Microsoft, Adobe or Apple
  2. Consistency with Other Standards - XForms was designed to be very consistent with other web standards such as CSS, XML Schema and XPath. If you know CSS then you can quickly learn how to style your XForms.
  3. Declarative - XForms is considered a declarative system in that it allows users to declare what they want the forms to do, not how to do it. Movement away from highly complex and primitive procedural JavaScript to advanced declarative styles is the principal way that non-programmers can participate in the forms development process.
  4. Less JavaScript - XForms allows the movement away from hard-to-maintain, difficult to debug and potentially insecure JavaScript
  5. Fewer "round trips" of pages being transferred from web server to web browser. This means that fewer web servers are needed in your DMZ and smaller bandwidth is needed between the client and the servers
  6. Clean and consistent use of MVC architectures
  7. Forms are easier to create, debug and maintain
  8. Forms can accommodate multiple languages and multiple currencies
  9. Forms have clear Separation of Concerns, meaning all your forms can share a common style sheet, model, bindings and presentation.
  10. Advanced user interface controls such as the XForms/Range control
  11. Extensibility of XForms (see XForms/Custom Controls)
  12. Allows the designer to focus on concrete business models and abstract user interfaces (attributed to Joern Turner)

The last point is very critical since business models are designed to be consistent with the business area that tend to be more constant over time. User interface technology on the other hand changes rapidly and must be highly contextual to a browser, browser version mobile device or table. This core philosophy of Separation of Concerns is one of the key elements to the philosophy of XForms and good human-machine interactions.

Disadvantages of XForms[edit]

Just to be fair, we should also mention the disadvantages. Most of these problems are related to the newness of XForms and will be mitigated over time:

  1. Web browser limitations have made it difficult for XForms tools vendors to support all XForms tags in all browsers
  2. Slow performance on very-large forms - forms with over 200 fields sometimes can be slow to load on some older browsers
  3. Using non-native browser forms players such as XSLTForms require an initial download of around 100K of JavaScript, CSS and XSL files that can be slow, especially over slower dial-up lines. Note that these files are usually cached on the local hard drive so that the second time a form package is used the files do not have to be re-downloaded.
  4. Lack of understanding of XML - Many traditional HTML/JavaScript forms developers are not familiar with XML standards
  5. Few complete working XForms examples and applications exist (a problem which we are trying to correct with this book)
  6. Few high-quality and low-cost GUI forms builder tools exist today (with the exception of IBM's Workplace forms, OpenOffice Forms, Onyx Forms and few other tools)

You will note that most of the disadvantages of XForms are related to limitations of XForms clients, current browser shortcomings, or skills and training issues. There are few fundamental architectural disadvantages with XForms.

Analysis of XForms Nay-sayers[edit]

When there is negative discussion about XForms we have found that most of the negative comments about XForms usually comes from people with one or more of the following attributes:

  • They don't understand the role that standards play in lowering the cost of software development
  • They are trying to promote a vendor-specific proprietary technology
  • They have very little actual real-world XForms experience or have not had strong mentorship by an experienced XForms consultant
  • They do not appreciate the architectural advantages of MVC-based systems and the use of dependency graphs
  • They are focused on the limitations of one or more specific browsers or XForms products
  • They are comparing XForms with a problem domain outside of the scope of XForms charter such as graphics or complex navigation controls

Next Page: Installing and Testing | Previous Page: Background

Home: XForms



Installing and Testing

XForms Client Options[edit]

There are several ways to get started using XForms. But we must first understand that running XForms within a web browser has several security-related issues that prevent software from saving to your local hard drive. There are several workarounds for this.

There are several XForms systems that can be used to build XForms. For example:

XSLTForms is a XForms implementation that can run within your browser or on the server. The client-based system run an XSLT transform within your browser.

BetterFORM is a server-side implementation of XForms that comes bundled with a native XML database (eXist-db).

There are JavaScript-based solutions and other plugins as well as web-server solutions available. See the Player Specific Instructions or the wikipedia page on XForms for more details. Note that these XForm solutions usually require you to download a web server and install Java Web Archive Files (War files) in the correct directory or add player-specific code to your examples.

FireFox Plugin[edit]

The FireFox plugin has limited support on the Mac and may not be supported in current versions of FireFox.

One of the most common today is Installing XForms in Firefox. This takes only about a minute to install so it is used by many of our students. Most of these exercises have been tested with the Firefox 0.7 extension on both Firefox 1.5 and Firefox 2.0.

Firefox 3.6 plugin: xForms 0.8.7

Firefox 2.0 plugin: FireFox 2.0 for the Mac

XForms Processors[edit]

XSLTForms uses XSLT and JavaScript in the browser to transform an XForms into HTML.

betterFORM processes XForms on the server with Java.

Orbeon Forms processes XForms on the server with Java.

All can be used with the eXist Native XML Database.

See also the Wikipedia article on XForms

Next Page: Naming Conventions | Previous Page: Benefits

Home: XForms



Naming Conventions

Here are some naming conventions used for this WikiBook. These naming conventions are designed to be consistent across the sample programs, allowing our students to be able to copy and paste blocks of code from the sample programs with a minimum amount of reformatting. So even though it may be a little bit annoying to have the xf: prefix on the XForms data elements, it does make it easy for students to quickly build new applications from the samples.

The audiences for much of this material are state and federal agencies that are converting paper forms to electronic forms. As a result we tend to use the XML Naming and Design Guidelines used by these organizations. Since these standards are built around ISO/IEC-11179 and other ebXML standards, they should not be too strange to most business developers.

There are over 150 of "Naming and Design Rule" guidelines but we don't need to use them all. A web site that discusses them is the Component Organization and Registration Environment web site.

Here are some guide lines to start out with:

Indentation[edit]

Please use three space characters to indent your examples. MediaWiki does not allow us to set tab stops and by default they are 8 characters.

Wrap XML Code in Source Tags[edit]

Please enclose all your sample XML code with the source tags with the lang="xml" attribute like this:

<source lang="xml">
 ....your XML code here...
</source>

Namespace Standards[edit]

Namespaces are core to XForms today and essential for our examples to work under a large number of diverse platforms. Please take some time to think carefully about namespaces and namespace prefixes.

Please use the following template at the head of your example:

<html 
   xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
   ...

Note that the first line:

xmlns="http://www.w3.org/1999/xhtml" 

indicates that the file uses XHTML as its default namespace. Any tags that do not have a namespace prefix are by default elements in the xhtml namespace.

We feel that keeping the examples in this default namespace will make students familiar with HTML more at home with XForms. Standard tags such as <h1>, <p>, <b> and <i> can be freely used in all our examples.

You can optionally add the XML processing instruction before the <html> tag:

<?xml version="1.0" encoding="UTF-8"?>

but most XForms systems do not need this. Any file that has a file extension of ".xhtml" implicitly implies that it is an XML file.

Warnings about DOCTYPE[edit]

Please do not put the !DOCTYPE tag in the header for xhtml1-strict.dtd. This specifically states that the file ONLY contains XHTML and most systems will not allow XForms tags when they see this. Many example programs have this and it should be removed to be correct.

XForms Player Specific Markup[edit]

Please do not put any player-specific markup in the examples. This book is about W3C standards, specifically XForms, CSS, XML Schema and XHTML. These examples should not require a specific implementation of a client forms player. If you are working with a specific player that does require special HTML tags, they can be automatically inserted by the web application server using an XML transform. This allows these examples to be used in a wide variety of classroom environments and by a large number of server and client XForms players.

For a general template see XForms/Template

For player specific instructions see Player Specific Instructions.

List of Example Program Naming Conventions[edit]

  1. Use a separate namespace for HTML, XForms controls and Data.
  2. Give HTML the default namespace. This makes it easy to take existing XHTML code and use it in the examples
    1. If it is not possible to give HTML a default namespace, give it a namespace prefix that is short, such as "h".
  3. Use the "xf" namespace prefix for XForm elements. I find about 3/4 of the examples use this already but some use the full "xform" or "xforms" prefix. I suggest avoiding the confusion and just use "xf" since it is short and in common use already.

Examples for US State and Federal Agencies[edit]

It is our hope that many US state and federal agencies may integrate this material into their training programs. This is an important audience for XForms since much of the XForms standards were promoted by agencies that did not allow JavaScript to be executed on their desktops for security reasons.

The namespace that we are using for most of our federal data model examples is the NIEM. The namespace prefix is "u" for "Universal" data elements for things like Address, Contact, Activity, Documents, Organizations, Person. The NIEM also has a very nice sub-schema generator that works very well with the process of building forms. See the niem.gov web site for more information on this. If you have any suggestions on any better tools then the NIEM tools, please let us know.

Next Page: Comparison of XForms Products | Previous Page: Installing and Testing

Home: XForms



Comparison of XForms Products

Motivation[edit]

You want to compare XForms browser products and understand each systems strengths and weaknesses.

Method[edit]

We first identify key attributes of each product and justify why an attribute is relevant in a high-level comparison. We then present a table of the products with one column for each attribute.

Key Attributes of XForms Product[edit]

Product Name and Current Version[edit]

License[edit]

What type of license is being used? Common options are Commercial (with link), Apache 2.0, LGPL, GPL or other. The column should always provide a URL to the exact license.

Cost Per 10 or 100 or 1,000 or 10,000 Users[edit]

What is the typical estimated costs for this product for between 10 and 10,000 users. Assume 10 medium-complexity forms used per person per day.

Client/Server/Both[edit]

Does the product convert the XForms code into browser-specific structures (HTML/JavaScript) on the client or the server?

Browsers Supported[edit]

What browsers are supported? Common items are All, C, F, I, O, S for Chrome, FireFox, IE, Opera and Safari.

XForms 1.1 Compatibility Tests[edit]

The W3C does provide a test suite for compatibility with the 1.1 specification. These test are rerun on a periodic basis.

Currently only a subset of products are being tested. The current test results are here

Version of XForms Supported[edit]

Options would be 1.0, 1.1

Key Limitations of Current Release[edit]

Status of XForms Compatibility Test[edit]

Did this product undergo a third party test of all of the features of XForms? If so, what percentage of the test pass. Provide a link to the test results.

Comparison Table[edit]

Client Side Applications[edit]

Product (Version) License Cost Implementation Architecture Browsers Test Results Strength Weakness Notes
EMC/Documentum Commercial See Documentum Google Web Toolkit Client All EMC Results
Chiba (3.0.0b2) liberal BSD and Apache 2 free Client DOJO with DWR 96% Chiba Results
Ubiquity Apache 2.0 free JavaScript All Test Results Not mature
Firefox Plugin Open source Free Browser Plugin Client Firefox 3.5 and earlier only [1] Very compliant with standard Firefox only, Limited Table Support, Limited Support, No Mac Version Innovative Product, Ideal for quick prototyping, Fast form loads for forms that do not have long selection lists
Formfaces Commercial JScript and HTML - No plugin required Client Very slow load times for medium forms, No large user base No updates to product since 2007
XSLTForms LGPL Free XSLT Tranformation Client or Server All Transform works on either server or client, Bundled with eXist and MarkLogic Not yet mature See XRX Wikibook
Picoforms Commercial See Picoforms IE Plugin Client Internet Explorer Only Ideal for internal forms for IE only sites Support not clear, Required Admin rights to install Limited Community Support

Server-Side Applications[edit]

(No XForms elements are sent to the client)

Product (Version) License Cost Implementation Architecture Browsers Test Results Strength Weakness Notes
XSLTForms LGPL Free XSLT Tranformation Client or Server All Bundled with eXist and MarkLogic Not yet mature
Orbeon Forms Open source Free Server-side transforms Server All Very Mature, Many Extensions, Excellent Support, Active Community Many examples require Orbeon Pipeline Language
BetterFORM BSD, Apache 2 Free Server-side transforms all written in Java Server All Test Results Very Mature, bundled with eXist, support for subforms, commercial support, active community, comes with graphical installer successor of Chiba Project
IBM Lotus Forms Commercial See IBM Server-side transform Server All Full Implementation, Very Mature, IBM Supported Price. Proprietary markup.

Next Page: HelloWorld | Previous Page: Naming Conventions

Home: XForms



HelloWorld

Background and Motivation[edit]

Since K&R wrote the first book on C programming, it has become tradition for programming books to begin with a "Hello World" program. Running this program will indicate if you have XForms installed correctly.

Here is a sample "hello world" program in XForms. It uses one input, one variable in the model, and one output. You should be able to just copy and paste the text into a program such as Notepad and save it to a file such as hello.htm. This will tell you if you have the Firefox or other browser extension installed correctly.

Screen Image[edit]

XForms-hello-world.jpg

(Note that this is only a .jpg and NOT an actual form!) textBold ttextext

Link to Working Example[edit]

Hello World

Hosted *hello world* example

Program[edit]

To run this program, just copy the following text into a file "hello.xhtml" and open it with your web browser with the appropriate XForms extension loaded.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Hello World in XForms</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <PersonGivenName/>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Type your first name in the input box. <br/>
        If you are running XForms, the output should be displayed in the output area.</p>   
         <xf:input ref="PersonGivenName" incremental="true">
            <xf:label>Please enter your first name: </xf:label>
         </xf:input>
         <br />
         <xf:output value="concat('Hello ', PersonGivenName, '. We hope you like XForms!')">
            <xf:label>Output: </xf:label>
         </xf:output>
   </body>
</html>

Problems[edit]

If this program does not work, you may not have the extension or plug-in installed in your browser.

For help see Installing XForms in FireFox.

Note that if you have the NoScript Firefox extension installed, you may need to configure NoScript to allow scripts from the location from which you are loading HelloWorld.

Also note, in Firefox the file has to be saved with a xhtml or xml extension. A file with a .html exension won't show the XForms.

Discussion[edit]

Note that the file looks much like a standard HTML file with a few exceptions.

  1. there is a namespace declaration at the beginning of the file and there are two elements with a xf: prefix in front of them.
  2. there is something called a model inside the HTML <head> element
  3. There are some new elements: input and output.

The two important lines are:

   <xf:input ref="PersonGivenName" incremental="true"/>

and

   <xf:output value="concat('Hello ', PersonGivenName, '. We hope you like XForms!')"/>

As the user types, this line takes the input that the user types in and copies it to the instance variable "PersonGivenName". Each time you type a character this program updates the output and using the XPath concat() function to wrap the string "Hello " in front of the name and the string ". We hope you like XForms!" after it.

You should also note that there is not a single line of JavaScript required to run this program. Getting rid of JavaScript is one of the biggest reasons people are migrating their applications to XForms.

Experiment[edit]

Try changing the input attribute incremental from:

 incremental="true"

to:

 incremental="false"

The output should update only after you enter "Tab" or press the "Enter" (Return) key.

Next Page: Simple Message | Previous Page: Comparison of XForms Products

Home: XForms



Simple Message

Motivation[edit]

This is a simple message in XForms. The user presses a button and they see an alert panel. This is an example of a modal message, which the user must respond to in order to continue using the form. We will cover two other types of message later.

Screen Image[edit]

Here is a screen image with the ephemeral message showing:

Link to working XForms Application[edit]

Simple Messages

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms"
 xmlns:ev="http://www.w3.org/2001/xml-events"
>
   <head>
      <title>XForms Message</title>
      <xf:model id="myModel">
         <xf:instance>
         <data>
            <MyMessage xmlns="">This is a modeless message stored directly in the model.
                Note you can drag me to the side and still proceed to the next task.</MyMessage>
            <inp1/>
            <inp2/>
         </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Put your cursor in the first input.  A message will appear for just a moment.</p>
         <xf:input ref="inp1">
            <xf:label>Ephemeral message: </xf:label>
            <xf:message level="ephemeral" ev:event="DOMFocusIn">This is an ephemeral message.
                Don't worry, I go away after a few seconds.</xf:message>
         </xf:input>
         <br/>
          <p>Press enter in the input field to get a modeless message:</p>
         <xf:input ref="inp2">
            <xf:label>Modeless message input: </xf:label>
            <xf:message level="modeless" model="myModel" ref="/data/MyMessage" ev:event="DOMActivate"/>
         </xf:input>
         <br/>
          <p>A standard and intrusive modal message that must be dismissed:</p>
         <xf:trigger>
            <xf:label>Press for a modal message</xf:label>
            <xf:message level="modal" ev:event="DOMActivate">This is a modal message.</xf:message>
         </xf:trigger>
   </body>
</html>

Discussion[edit]

The data for the first and last message come from the body of the document. The modeless message is taken directly from the body by using an XPath expression into the model.

Note that the first event happens when you start to enter data in an input field. This is the DOMFocusIn event. The other two use the DOMActivate event which happens when you enter a return on the second example and press the button on the last example.

--the above explanation does not appear to refer to the Simple Message example ! --EXAMPLE FIXED

Example not working in my environment. eXist, jetty, betterFORM, firefox. Result is a betterFORM message: xforms-binding-exception: model 'myModel' not found XPath: /html[1]/body[1]/xf:input[2]/xf:message[1]

This above error was because the id of the element was not set. partly fixed now with <xf:model id="myModel">, but still not getting modeless message


Next Page: XForms Architecture | Previous Page: HelloWorld

Home: XForms



XForms Architecture

The XForms Architecture[edit]

Unlike some technologies, e.g. AJAX, XForms is much more than a collection of languages and techniques. XForms has a fully developed architecture and a complete set of design patterns.

To start with let's look at the heart of XForms architecture: The Model-View-Controller design pattern.

Most people that have studied MVC architecture agree on two aspects: The Model and the View. The model is where you store your data or your business objects. The View is what the user sees. But many variations of MVC have very different implementations of a controller. In the early days of SmallTalk at Xerox PARC the controller was related to user events and how they are gathered and dispatched. Today our input controls have much of the heavy lifting of events "baked into" them, so the form designers don't have to worry too much about handling mouse events and redirecting them unless they want specific behaviors. Many forms can be created without any knowledge of how events work.

To understand how XForms work you must understand that XForms has two trees in the browser.

The model is a tree that is not presented to the user directly and holds one or more instances and optionally some binding rules and some named events.

The view is a tree of presentation elements that the user sees. To build an XForms application you simply wire the two trees together using binding statements. And there are several ways to do this.

Next Page: Input Example | Previous Page: Simple Message

Home: XForms



Input Example

Basic Form Input[edit]

One of the most common user interface controls in a web form is a simple, one-line text field. In this example we have a very simple form with two input fields. Each input has its own label to the left of the input field.

XForms-input.jpg

Link to XForms Application[edit]

Input Fields

Program Structure[edit]

Our program has two parts, a model and a view. The model has instance data in it to store the values that the user enters in the form. The view is part of the presentation in the body of the HTML document.

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>XForms inputs with labels</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <PersonGivenName/>
               <PersonSurName/>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Enter your first name, and last name.</p>
         <xf:input ref="PersonGivenName" incremental="true">
            <xf:label>First Name:</xf:label>
            <xf:hint>Also known as given name.</xf:hint>
         </xf:input>
         <br/>
         <xf:input ref="PersonSurName" incremental="true">
            <xf:label>Last Name:</xf:label>
            <xf:hint>Also known as sur name or family name.</xf:hint>
         </xf:input>
         <br/>
         <br/>
         Output First Name: <b><xf:output ref="PersonGivenName"/></b>
         <br/>
         Output Last Name: <b><xf:output ref="PersonSurName"/></b>
      <p>Note that as you type the model output will be updated.</p>
   </body>
</html>

Hints[edit]

You can also provide the user with data entry hints using the <xf:hint> element.

Discussion[edit]

Notice that as you type, the output gets immediately updated. This is because the XForms input control has an incremental="true" attribute.

Our model is simple, just the first and last name of a person.

Note that the label and hint tags are nested INSIDE the input tags.

References[edit]

W3C XForms specification for input control

Next Page: Incremental Many to One | Previous Page: XForms Architecture

Home: XForms



Incremental Many to One

Motivation[edit]

Sometimes a single input field will be used to create a new output. Not only does the input field need to be updated, but other fields that depend on this input also need to change.

Here is an example program that has three input fields. As an example, it uses a data dictionary entry (called a Data Element). The name of the Data Element is a concatenation of three fields: the Object Class Name, the Property Name and the Representation Term. The first two are text fields and the third is a value that is picked from a list.

This form creates a single output based on the values of the input fields. This shows that the model can take many different inputs and create a single output.

Link to working XForms Application[edit]

Load XForms Application

Sample Code[edit]

<html
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xf="http://www.w3.org/2002/xforms">
<head>
    <title>Many to one</title>
    <xf:model>
         <xf:instance xmlns="">
            <DataElement>
               <ObjectClassName />
               <PropertyName />
               <RepresentationTerm />
            </DataElement>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <xf:group nodeset="/DataElement">
         <fieldset>
            <legend>Data Element Name</legend>
            <xf:label>DataElementName: </xf:label>
            <xf:output value="concat(ObjectClassName, ' ', PropertyName, ' ', RepresentationTerm)"/>
            <p>
               <xf:input ref="ObjectClassName" incremental="true">
                  <xf:label>Object Name:</xf:label>
               </xf:input>
            </p>
            <p>
               <xf:input ref="PropertyName" incremental="true">
                  <xf:label>Property Name:</xf:label>
               </xf:input>
            </p>
            <p>
               <xf:select1 ref="RepresentationTerm" incremental="true">
                  <xf:label>Representation Term:</xf:label>
                  <xf:item>
                     <xf:label>Amount</xf:label>
                     <xf:value>Amount</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>Code</xf:label>
                     <xf:value>Code</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>Count</xf:label>
                     <xf:value>Count</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>ID</xf:label>
                     <xf:value>ID</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>Indicator</xf:label>
                     <xf:value>Indicator</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>Name</xf:label>
                     <xf:value>Name</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>Percent</xf:label>
                     <xf:value>Percent</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>Text</xf:label>
                     <xf:value>Text</xf:value>
                  </xf:item>
               </xf:select1>
            </p>
         </fieldset>
      </xf:group>
   </body>
</html>

Discussion[edit]

How can you then take that output and put it back into the model? This will be covered later in the tutorial.

Next Page: Spreadsheet like updating | Previous Page: Input Example

Home: XForms



Spreadsheet like updating

Updating the Model[edit]

Many developers of traditional JavaScript-based forms are not accustomed to variables automatically updating for them. With XForms, you can easily create a complex system where XForms automatically figures out what cells to update. This is similar to using a spreadsheet. A dependency graph is automatically created for you and the appropriate cells are automatically updated if an input they depend upon changes.

Here is an example program that demonstrates this.

Screen Image[edit]

Here is a screen capture of the application:

XForms-spreadsheet-update.jpg

Note that top grid is actually just unlabeled input cells. Below that is a sample output inside a table. You should be able to change any of the input cells, enter a tab, and see the output and the footer calculations change.

Link to Working XForms Application[edit]

Spreadsheet-like Updating

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <head>
      <title>XForms Spreadsheat like Update</title>
      <style type="text/css">
    table {
       font-family: Arial, Helvetica, sans-serif;
        border-collapse: collapse;
      }
      
    th {
        color: white;
        background-color: black;
      }
    
    .output tr td {
       border: solid black 1px;
       padding: 2px;
       text-align: center;
    }
    </style>
      <xf:model>
         <xf:instance>
            <Spreadsheet xmlns="">
               <Row>
                  <A>10</A>
                  <B>20</B>
                  <C>30</C>
               </Row>
               <Row>
                  <A>40</A>
                  <B>50</B>
                  <C>60</C>
               </Row>
               <Row>
                  <A>70</A>
                  <B>80</B>
                  <C>90</C>
               </Row>
               <Results>
                  <sum/>
                  <avg/>
                  <min/>
               </Results>
            </Spreadsheet>
         </xf:instance>
         <xf:bind nodeset="/Spreadsheet/Results/sum" calculate="sum(/Spreadsheet/Row/A)" type="xs:decimal" />
         <xf:bind nodeset="/Spreadsheet/Results/avg" calculate="avg(/Spreadsheet/Row/B)" type="xs:decimal" />
         <xf:bind nodeset="/Spreadsheet/Results/min" calculate="min(/Spreadsheet/Row/C)" type="xs:decimal" />
      </xf:model>
   </head>
   <body>
      <xf:group ref="/Spreadsheet">
         <xf:input ref="Row[1]/A">
            <xf:label></xf:label>
         </xf:input>
         <xf:input ref="Row[1]/B">
            <xf:label></xf:label>
         </xf:input>
         <xf:input ref="Row[1]/C">
            <xf:label></xf:label>
         </xf:input>
         <br/>
         <xf:input ref="Row[2]/A">
            <xf:label></xf:label>
         </xf:input>
         <xf:input ref="Row[2]/B">
            <xf:label></xf:label>
         </xf:input>
         <xf:input ref="Row[2]/C">
            <xf:label></xf:label>
         </xf:input>
         <br/>
         <xf:input ref="Row[3]/A">
            <xf:label></xf:label>
         </xf:input>
         <xf:input ref="Row[3]/B">
            <xf:label></xf:label>
         </xf:input>
         <xf:input ref="Row[3]/C">
            <xf:label></xf:label>
         </xf:input>
         <table class="output">
            <thead>
               <tr>
                  <th>#</th>
                  <th>A</th>
                  <th>B</th>
                  <th>C</th>
               </tr>
            </thead>
            <tbody>
               <tr>
                  <td>
                     <xf:output value="1" />
                  </td>
                  <td>
                     <xf:output ref="Row[1]/A" />
                  </td>
                  <td>
                     <xf:output ref="Row[1]/B" />
                  </td>
                  <td>
                     <xf:output ref="Row[1]/C" />
                  </td>
               </tr>
               <tr>
                  <td>
                     <xf:output value="2" />
                  </td>
                  <td>
                     <xf:output ref="Row[2]/A" />
                  </td>
                  <td>
                     <xf:output ref="Row[2]/B" />
                  </td>
                  <td>
                     <xf:output ref="Row[2]/C" />
                  </td>
               </tr>
               <tr>
                  <td>
                     <xf:output value="3" />
                  </td>
                  <td>
                     <xf:output ref="Row[3]/A" />
                  </td>
                  <td>
                     <xf:output ref="Row[3]/B" />
                  </td>
                  <td>
                     <xf:output ref="Row[3]/C" />
                  </td>
               </tr>
               <tr>
                  <td />
                  <td>Sum=<xf:output ref="Results/sum" />
                  </td>
                  <td>Avg=<xf:output ref="Results/avg" />
                  </td>
                  <td>Min=<xf:output ref="Results/min" />
                  </td>
               </tr>
            </tbody>
         </table>
      </xf:group>
   </body>
</html>

Discussion[edit]

Due to limitations with some of the XForms implementations this example does not use the "repeat" command but just addresses each cell directly by its address.

Suggested Improvements[edit]

This example could be a lot simpler if we used the repeat-nodeset statement in a table. This currently does not work with input cells using FormFaces.

Next Page: Bind | Previous Page: Incremental Many to One

Home: XForms



Bind

Motivation[edit]

There are three core concepts that you will learn in building XForms applications:

  1. The model is a tree of data elements
  2. The presentation is a tree of data elements
  3. To build your form, these two trees need to be wired together - this is called "binding"

Many of the exercises in this cookbook give examples of this binding. This process is a small example of how this can work. In practice there are many ways to bind the user interface to the model.

Screen Image[edit]

The screen image is similar to input programs from a prior example. This example has two input fields for a person's first and last name and two output controls.

Xforms-input.jpg

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <head>
      <title>Your Title Here</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <PersonGivenName/>
               <PersonSurName/>
            </data>
         </xf:instance>
         <xf:bind id="PersonGivenName" nodeset="/data/PersonGivenName"/>
         <xf:bind id="PersonSurName" nodeset="/data/PersonSurName"/>
      </xf:model>
   </head>
   <body>
       <xf:input bind="PersonGivenName" incremental="true">
          <xf:label>Input First Name:</xf:label>
       </xf:input>
       <br/>
       <xf:input bind="PersonSurName" incremental="true">
          <xf:label>Input Last Name:</xf:label>
       </xf:input>
       <br/>
       <xf:output bind="PersonGivenName">
          <xf:label>Output First Name:</xf:label>
       </xf:output>
       <br/>
       <xf:output bind="PersonSurName">
          <xf:label>Output Last Name:</xf:label>
       </xf:output>
   </body>
</html>

Discussion[edit]

Here are the two lines in the model that bind the data element paths to identifiers:

  <xf:bind id="PersonGivenName" nodeset="/data/PersonGivenName"/>
  <xf:bind id="PersonSurName" nodeset="/data/PersonSurName"/>

Note that bind uses nodeset, not ref to specify the path name to the leaf element in the instance document.

After this is done, each user interface element that inputs or outputs the data elements just adds the bind attribute:

 <xf:input bind="PersonGivenName">

We should also note that in this case there is a single input and a single output for each data element. This does not need to be the case. A single input can be bound to many outputs and an output could also depend on many inputs. An example of this would be using the "calculate" attribute of the bind statement.

Bind attributes[edit]

Here are the following attributes of the bind element and a short description of how they are used:

type

  • Associate an instance variable with a specific XML Schema data type
  • Extend or restrict schema type definitions

relevant

  • Enabling or disable controls based on the values of data elements in the model

required

  • Conditionally make fields required based on the values of data elements in the model

readonly

  • Disable editing of fields based on model data elements such as role

constraint

  • Create complex schema constraints between two or more data elements
  • Set the limits of minimum or maximum values of a node-set

calculate

  • Creating computational dependency among data elements
  • Compute the value of new data elements based on other data elements
  • Enable spread-sheet like calculations within XForms

Next Page: Adder | Previous Page: Spreadsheet like updating

Home: XForms



Adder

Motivation[edit]

This program demonstrates several different ways to call a web service from a sample XForms application. The example uses both HTTP POST and HTTP GET methods and shows how the results are returned into an instance in the model and how the page can be replaced with the results. The web service it calls is a simple web service that adds two numbers together.

Screen Image[edit]

XForms Adder Example After Execution

Link to XForms Application[edit]

For the results to be put in the model using FireFox, make sure to add www.cems.uwe.ac.uk and xforms-examples.googlecode.com to your XForms white list using the Tools/Options/Security/Allowed Sites menu of FireFox. This is required since our web forms are hosted at one domain but the web services are hosted on another domain.

Load XForms Application

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   xmlns:ev="http://www.w3.org/2001/xml-events" >
    <head>
        <title>XQuery Tester</title>
        <style type="text/css">
            @namespace xf url("http://www.w3.org/2002/xforms");        
            body {font-family: Arial,sans-serif;}
            
            xf|input, xf|output {
               display: table-row;
               line-height: 2em;
            }
            
            xf|label {
               display: table-cell;
               text-align: right;
               font-family: Arial, Helvetica, sans-serif;
               font-weight: bold;
               font-size: small;
               padding-right: 5px;
               width: 150px;
            }  
        </style>
        <xf:model>
            <xf:instance xmlns="" id="input-parameters">
                <data>
                    <arg1>123</arg1>
                    <arg2>456</arg2>
                </data>
            </xf:instance>
            <xf:instance xmlns="" id="submit-results">
                <results>
                    <sum/>
                </results>
            </xf:instance>
            
            <xf:submission id="get-instance" method="get" replace="instance" instance="submit-results"
                action="http://www.cems.uwe.ac.uk/xmldb/rest/db/Wiki/adder.xq"
                separator="&amp;">
                <xf:toggle case="case-busy" ev:event="xforms-submit"/>
                <xf:toggle case="case-submit-error" ev:event="xforms-submit-error"/>
                <xf:toggle case="case-submit-done" ev:event="xforms-submit-done"/>
            </xf:submission>          
            
            <xf:submission id="get-replace" method="get" replace="all" instance="submit-results"
                action="http://www.cems.uwe.ac.uk/xmldb/rest/db/Wiki/adder.xq"
                separator="&amp;">
                <xf:toggle case="case-busy" ev:event="xforms-submit"/>
                <xf:toggle case="case-submit-error" ev:event="xforms-submit-error"/>
                <xf:toggle case="case-submit-done" ev:event="xforms-submit-done"/>
            </xf:submission>
            
            <xf:submission id="post-instance" method="post" 
                replace="instance" instance="submit-results" 
                action="hhttp://www.cems.uwe.ac.uk/xmldb/rest/db/Wiki/adder-post.xq">
                <xf:toggle case="case-busy" ev:event="xforms-submit"/>
                <xf:toggle case="case-submit-error" ev:event="xforms-submit-error"/>
                <xf:toggle case="case-submit-done" ev:event="xforms-submit-done"/>
            </xf:submission>
            
            <xf:submission id="post-replace" method="post"
                action="http://www.cems.uwe.ac.uk/xmldb/rest/db/Wiki/adder-post.xq">
                <xf:toggle case="case-busy" ev:event="xforms-submit"/>
                <xf:toggle case="case-submit-error" ev:event="xforms-submit-error"/>
                <xf:toggle case="case-submit-done" ev:event="xforms-submit-done"/>
            </xf:submission>
            
            <xf:submission id="get-test" method="get" replace="all" 
                separator="&amp;"
                action="http://xformstest.org/cgi-bin/showinstance.sh"/>
            
            <xf:submission id="post-test" method="post" replace="all" 
                action="http://xformstest.org/cgi-bin/showinstance.sh"/>
        </xf:model>
    </head>
    <body>
        <h1>Using XForms to test XQuery</h1>
        <p>Note, you must have xforms-examples.googlecode.com and www.cems.uwe.ac.uk in your whitelist for this demo to work.</p>
       
        <xf:input ref="arg1" incremental="true">
            <xf:label>Arg1:</xf:label>
        </xf:input>
        <xf:input ref="arg2" incremental="true">
            <xf:label>Arg2:</xf:label>
        </xf:input>
        
        <xf:output ref="instance('submit-results')/sum">
            <xf:label>Sum:</xf:label>
        </xf:output>
        
        <xf:submit submission="get-instance">
            <xf:label>HTTP GET -> instance</xf:label>
        </xf:submit>
        <br/>
        
        <xf:submit submission="post-instance">
            <xf:label>HTTP POST -> instance</xf:label>
        </xf:submit>
        <br/>
        
        <xf:submit submission="get-replace">
            <xf:label>HTTP GET -> replace</xf:label>
        </xf:submit>
        <br/>
        
        <xf:submit submission="post-replace">
            <xf:label>HTTP POST -> replace</xf:label>
        </xf:submit>
        <br/>
        
        <xf:submit submission="get-test">
            <xf:label>HTTP Get Test</xf:label>
        </xf:submit>
        <br/>
        <xf:submit submission="post-test">
            <xf:label>HTTP Post Test</xf:label>
        </xf:submit>
        <br/>
        
        <xf:switch>
            <xf:case id="ready"/>
            <xf:case id="case-busy">
                <p>Waiting for results from server...</p>
            </xf:case>
            <xf:case id="case-submit-error">
                <p>Submit error</p>
            </xf:case>
            <xf:case id="case-submit-done">
                <p>Submit done</p>
            </xf:case>
        </xf:switch>
    </body>
</html>

Discussion[edit]

Next Page: Input | Previous Page: Bind

Home: XForms



Input

Basic Form Input[edit]

One of the most common user interface controls in a web form is a simple, one-line text area. In this example we have a very simple form with two input fields. Each input has its own label to the left of the input field.

XForms-input.jpg

Link to XForms Application[edit]

Input Fields

Program Structure[edit]

Our program has two parts, a model and a view. The model has instance data in it to store the values that the user enters in the form. The view is part of the presentation in the body of the HTML document.

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>XForms inputs with labels</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <guru/>
               <PersonSurName/>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Enter your first name, and last name.</p>
         <xf:input ref="PersonGivenName" incremental="true">
            <xf:label>Input First-Name:</xf:label>
            <xf:hint>Also known as given name.</xf:hint>
         </xf:input>
         <br/>
         <xf:input ref="PersonSurName" incremental="true">
            <xf:label>Input Last Name:</xf:label>
            <xf:hint>Also known as sur name or family name.</xf:hint>
         </xf:input>
         <br/>
         <br/>
         Output First Name: <b><xf:output ref="PersonGivenName"/></b>
         <br/>
         Output Last Name: <b><xf:output ref="PersonSurName"/></b>
      <p>Note that as you type the model output will be updated.</p>
   </body>
</html>

Hints[edit]

You can also provide the user with data entry hints using the <xf:hint> element.

Discussion[edit]

Notice that as you type, the output gets immediately updated. This is because the XForms input control has an incremental="true" attribute.

Our model is simple, just the first and last name of a person.

Note that the label and hint tags are nested INSIDE the input tags.

References[edit]

W3C XForms specification for input control

Next Page: Address | Previous Page: Adder

Home: XForms



Address

Here is a simple address form. Note that HTML is the default namespace. We interleave both XForms and HTML tags but the XForms tags have xf as a prefix. We use the HTML fieldset and legend tags to put related form elements in a group. We use the XForms group element to tell us where in the model to get our instance data.

Link to XForms Application[edit]

Load XForms Application

Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Address Form</title>
      <xf:model>
         <xf:instance>
            <Address xmlns="">
               <LocationStreetFullText />
               <LocationCityName />
               <LocationStateName />
               <LocationPostalID />
            </Address>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <xf:group ref="/Address">
         <fieldset>
            <legend>Mailing Address</legend>
            <xf:input ref="LocationStreetFullText">
               <xf:label>Street: </xf:label>
            </xf:input>
            <br />
            <xf:input ref="LocationCityName">
               <xf:label>City:</xf:label>
            </xf:input>
            <br />
            <xf:input ref="LocationStateName">
               <xf:label>State:</xf:label>
            </xf:input>
            <br />
            <xf:input ref="LocationPostalID">
               <xf:label>Postal Code:</xf:label>
            </xf:input>
         </fieldset>
      </xf:group>
   </body>
</html>

Discussion[edit]

The form labels are not lined up very nicely. This can be done by adding a few lines of cascading style sheet to the program.

Note that the data uses an upper camel case naming convention used in ebXML, ACORD, UBL, GMXDM, NIEM and other US federal naming and design conventions.


Next Page: Address Aligned | Previous Page: Input

Home: XForms



Address Aligned

Using CSS to Align Form Fields[edit]

Forms are much easier to use if they are aligned. This example uses CSS table structures to align our form. It turns groups into tables, inputs into rows and labels and values into cells.

Screen Image[edit]

XForms-address-aligned.jpg

Link to XForms Application[edit]

Address Aligned

Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Address Form Aligned Using CSS</title>
      <style type="text/css"><![CDATA[
      /* a stylesheet for X-Forms input field alignment */

@namespace xf url("http://www.w3.org/2002/xforms");

/* give the input form labels and the fieldset legend a bold sans-serif font */
label, legend {
   font-family: Arial, Helvetica, sans-serif;
   font-weight: bold;
}

/* give the fieldset some breathing room */
fieldset {
   padding: 5px;
   width: 260px;
}

/* the labels are right-aligned in a 150px wide column */
xf|label {
   width: 150px;
   margin: 3px;
   text-align: right;
}

/* the input values are left aligned */
xf|value {
   text-align: left;
}

/* vertical area between input boxes */
input {
   margin: .2em;	
}

/* each group is our table */
xf|group {
   display: table;
}

/* each input is a row in the group table */
xf|input {
   display: table-row;
}

/* each label within an input is a cell in the input row */
xf|input xf|label {
   display: table-cell;	
}

/* each value (pseudo-element) is also a cell in the input row */
xf|input::value {
   display: table-cell;
}
]]>
</style>
      <xf:model>
         <xf:instance xmlns="">
            <Address>
               <LocationStreetFullText />
               <LocationStreetFullText2 />
               <LocationCityName />
               <LocationStateName />
               <LocationPostalID />
            </Address>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <xf:group>
         <fieldset>
            <legend>Mailing Address</legend>
            <xf:input ref="LocationStreetFullText">
               <xf:label>Street: </xf:label>
            </xf:input>
            <xf:input ref="LocationStreetFullText2">
               <xf:label />
            </xf:input>
            <xf:input ref="LocationCityName">
               <xf:label>City:</xf:label>
            </xf:input>
            <xf:input ref="LocationStateName">
               <xf:label>State:</xf:label>
            </xf:input>
            <xf:input ref="LocationPostalID">
               <xf:label>Postal Code:</xf:label>
            </xf:input>
         </fieldset>
      </xf:group>
   </body>
</html>

Discussion[edit]

This style sheet only covers the XForms <xf:input> tags. It will need additions if you want to align select, select1, textarea and other controls. A full CSS file for doing this is described later on in this cookbook.

Note that you MUST put inputs inside of a group element for this stylesheet to work.

Also note that the table can grow if the labels get too long.

Note that the display: table properties work in FireFox but may not work in older browsers that do not support table layout.

Alternative layout strategy using float:left[edit]

You can control the width of the label column by the odd interaction of the float:left CSS control and the block display. Basically if you try to control the width of a block it may not work unless you also add the float:left to label.

Here is the CSS that works for this:

/* This line ensures all the separate input controls appear on their own lines */
xf|input, xf|select, xf|select1, xf|textarea {display:block; margin:5px 0;}

/* Makes the labels right aligned in a 250px wide column that floats to the left of the input controls. */
xf|input > xf|label, xf|select > xf|label, xf|select1 > xf|label, xf|textarea > xf|label 
{text-align:right; padding-right:10px; width:250px; float:left; text-align:right;}

Note that some older browsers do not support the child (greater than) selector correctly.

Next Page: Input Field Width | Previous Page: Address

Home: XForms



Input Field Width

Motivation[edit]

Sometimes you want to be able to control the field width, even though the default input text scrolls. This can be done for the entire form or for on a field-by-field basis for all input fields within a form. For example if you have three places that a person's last name occurs they can all be controlled by changing a single CSS file that is imported into the form. This CSS file can also be generated directly from an XML Schema or metadata registry using XML transforms.

Screen Image[edit]

Screen Image of CSS controled field widths using the FireFox XForms extension and the .xf-value selector

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <head>
      <title>Controlling Input Field Width</title>
      <style type="text/css"><![CDATA[
   @namespace xf url("http://www.w3.org/2002/xforms");
   body {
      font-family: Helvetica;sans-serif;
   }
   
   label, legend {
      font-weight: bold;
   }

   /* The default field width for all inputs */
   .xf-value {
      width: 100px
   }

   /* custom field width overrides relative to current font size */
   /* ex is the size of the current lowercase 'x' in pixels */
   /* em is the size of the current "M" character in pixels */
   .PersonGivenName .xf-value {width:20ex}
   .PersonMiddleName .xf-value {width:15ex}
   .PersonSurName .xf-value {width:25ex}
   .LocationCityName .xf-value {width:20ex}
   .LocationStateCode .xf-value {width:2em}
   .LocationPostalID .xf-value {width:10ex}
]]>
   </style>
      <xf:model>
         <xf:instance xmlns="">
            <Data>
               <PersonGivenName>John</PersonGivenName>
               <PersonMiddleName>George</PersonMiddleName>
               <PersonSurName>Doe</PersonSurName>
               <LocationCityName>Anytown</LocationCityName>
               <LocationStateCode>MM</LocationStateCode>
               <LocationPostalID>55123-1234</LocationPostalID>
            </Data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <fieldset>
      <legend>Name and Address</legend>
       <xf:input class="PersonGivenName" ref="/Data/PersonGivenName" incremental="true">
         <xf:label>First:</xf:label>
       </xf:input>
       <xf:input class="PersonMiddleName"  ref="/Data/PersonMiddleName" incremental="true">
         <xf:label>Middle:</xf:label>
       </xf:input>
       <xf:input class="PersonSurName" ref="/Data/PersonSurName" incremental="true">
         <xf:label>Last:</xf:label>
       </xf:input>
       <br/>
       <xf:input class="LocationCityName" ref="/Data/LocationCityName" incremental="true">
         <xf:label>City:</xf:label>
       </xf:input>
       <xf:input class="LocationStateCode" ref="/Data/LocationStateCode" incremental="true">
         <xf:label>State:</xf:label>
       </xf:input>
       <xf:input class="LocationPostalID" ref="/Data/LocationPostalID" incremental="true">
         <xf:label>Postal:</xf:label>
       </xf:input>
       </fieldset>

       <xf:output ref="/Data/PersonGivenName">
         <xf:label>First Name:</xf:label>
       </xf:output>
       <br/>
       <xf:output ref="/Data/PersonMiddleName">
         <xf:label>Middle Name:</xf:label>
       </xf:output>
       <br/>
       <xf:output ref="/Data/PersonSurName">
         <xf:label>Last Name:</xf:label>
       </xf:output>
        <br/>
        <xf:output ref="/Data/LocationCityName">
         <xf:label>City Name:</xf:label>
       </xf:output>
        <br/>
       <xf:output ref="/Data/LocationStateCode">
         <xf:label>State Code:</xf:label>
       </xf:output>
       <br/>
       <xf:output ref="/Data/LocationPostalID">
         <xf:label>Postal Code:</xf:label>
       </xf:output>
       <br/>
   </body>
</html>

Discussion[edit]

There are many tradeoffs as to where to put form width information. Ideally it would be generated by a script from a metadata registry. One of the questions concerns if a data element length should only have a default recommended value in a semantic registry and the actual constraints be stored in a constraint schema. We all know that zip codes should be 5 or 9 digits and that a 12 digit zip code may only have meaning in a specific context.

This example has been tested using the FireFox browser. The use of the .xf-value class selector may not work on other systems.

Note:
Inline styles within an input field:

<xf:input style=".xf-value {width: 10em}">

does not work.

Next Page: Secret | Previous Page: Address Aligned

Home: XForms



Secret

The XForms secret control[edit]

People that are sitting near you should not be able to see your password as you enter it. The secret control echos a "*" to the screen for each character you type.

Screen Image[edit]

Here is what the user interface would look like:

Login Screen Using HTML Fieldset and Legend Formatting

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Sample XForms Login</title>
      <style type="text/css"><![CDATA[
   @namespace xf url("http://www.w3.org/2002/xforms");
  
  xf|group {
     display: table;
   }
   
   xf|input, xf|secret {
      display: table-row;
   }
   
   xf|value {
      text-align: left;
   }

  xf|label, legend {
      display: table-cell;
      font-family: Arial, Helvetica, sans-serif;
      font-weight: bold;
      text-align: right;
      width: 100px;
   }
]]>      
</style>
      <xf:model>
         <xf:instance xmlns="">
            <Login>
               <LoginID />
               <Password />
            </Login>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <fieldset>
         <legend>System Login</legend>
      <xf:input ref="LoginID">
         <xf:label>Login: </xf:label>
      </xf:input>
      <br />
      <xf:secret ref="Password">
         <xf:label>Password: </xf:label>
      </xf:secret>
      </fieldset>
   </body>
</html>

Testing[edit]

The login characters should be echoed back but the password field should just echo a "*" character for every character the user types.

Discussion[edit]

The values for the login and password are stored directly in the model.

This example uses a CSS style sheet to put the labels and fieldset legend in bold and align the login and password labels.

By default the fieldset box stretches the entire width of the page. You can make it static by adding a style attribute with the width set to 250 pixels like this:

 <fieldset style="width: 250px;">


Next Page: Message Types | Previous Page: Input Field Width

Home: XForms



Message Types

Motivation[edit]

With JavaScript you did not have much choice in how intrusive you were about alerting a user. The JavaScript alert() function required the user to acknowledge a message before they proceeded in filling out a form. With XForms there are now three ways to proceed. Each has a different level of intrusiveness. There are three message options:

  1. ephemeral - a message that just appears briefly and goes away by itself
  2. modeless - a message you can ignore for now
  3. modal - a message the user must acknowledge before you go on

Screen Image[edit]

Here is a sceen image with the ephemeral message showing:

XForms-message-types.jpg

Link to working XForms Application[edit]

Simple Messages

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms"
 xmlns:ev="http://www.w3.org/2001/xml-events"
>
   <head>
      <title>XForms Message</title>
      <xf:model id="myModel">
         <xf:instance>
            <MyMessage xmlns="">This is a modeless message stored directly in the model.
                Note you can drag me to the side and still proceed to the next task.
            </MyMessage>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Put your cursor in the first input.  A message will appear for just a moment.</p>
         <xf:input>
            <xf:label>Ephemeral message: </xf:label>
            <xf:message level="ephemeral" ev:event="DOMFocusIn">This is an ephemeral message.
                Don't worry, I go away after a few seconds.</xf:message>
         </xf:input>
         <br/>
          <p>Press enter in the input field to get a modeless message:</p>
         <xf:input>
            <xf:label>Modeless message input: </xf:label>
            <xf:message level="modeless" model="myModel" ref="/MyMessage" ev:event="DOMActivate"/>
         </xf:input>
         <br/>
          <p>A standard and intrusive modal message that must be dismissed:</p>
         <xf:trigger>
            <xf:label>Press for a modal message</xf:label>
            <xf:message level="modal" ev:event="DOMActivate">This is a modal message.</xf:message>
         </xf:trigger>
   </body>
</html>

Discussion[edit]

The data for the first and last message come from the body of the document. The modeless message is taken directly from the body by using an XPath expression into the model.

Note that the first event happens when you start to enter data in an input field. This is the DOMFocusIn event. The other two use the DOMActivate event which happens when you enter a return on the second example and press the button on the last example.

Next Page: Textarea | Previous Page: Secret

Home: XForms



Textarea

Motivation[edit]

The user may enter more text than used in a typical single line input field and/or the programmer wants to use a large block of multi-line text to capture user input.

Method[edit]

When you have text input that spans multiple lines you can use the <textarea> control. The format of the textarea control is the following:

<xf:textarea ref="XPathExpression">
   <xf:label>Note:</xf:label>
</xf:textarea>

Screen Image[edit]

Here is a screen image using the FireFox XForms extension:

XForms textarea control with label

Note that the label is aligned at the bottom of the left edge.

Sample Style Sheet[edit]

Here is some sample CSS code that changes all of the text areas in a form to be 7 characters high and 500 pixels wide.

textarea {
   font-family: sans-serif;
   height: 8em;
   width: 600px;
}

Sample Program[edit]

<html 
   xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>XForms textarea</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <MyTextValue />
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>

<xf:input ref="Name" incremental="true">
            <xf:label> Name:</xf:label>
</xf:output ref="Name">
      <xf:textarea ref="MyTextValue">
         <xf:label>Note:</xf:label>
      </xf:textarea>
   </body>
</html>

Discussion[edit]

One of the challenges is to be able to format the size of the textarea correctly. This is usually done in a style sheet.

Aligning the labels[edit]

Some forms place textareas within tables. These tables put the labels on the left cell and the textarea input box on the right. The following CSS will then align the labels at the top of the row.

/* align the label at the top of the left area */
xf|textarea > xf|label {
   vertical-align: top;
}

Next Page: Textarea with style | Previous Page: Message Types

Home: XForms



Textarea with style

Motivation[edit]

The default layout for a textarea is often not what you want. The size of the textarea may not be correct or the label may not be positioned correctly. This program shows you how to change this.

Screen Image[edit]

Here is a sample screen image. The example includes the default textarea and a small, medium, large and extra large version. Note that if the content exceeds the textarea a scroll bar is automatically added to the control.

Textarea styled with CSS

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>XForms textarea demo</title>
      <link rel="stylesheet" type="text/css" href="textarea.css" />
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <Default>Default Default Default Default</Default>
               <Small>Small Small Small Small Small Small Small Small Small Small Small
               Small Small Small Small Small Small Small </Small>
               <Medium>Medium Medium Medium Medium Medium Medium Medium Medium Medium Medium
               Medium Medium Medium Medium Medium Medium Medium Medium Medium Medium Medium
               Medium Medium Medium Medium Medium Medium Medium Medium Medium Medium</Medium>
               <Large>Large Large Large Large Large Large Large Large Large Large Large Large
               Large Large Large Large Large Large Large Large Large Large Large Large Large
               Large Large Large Large Large Large Large Large Large Large Large Large Large
               Large Large Large Large Large Large Large Large Large Large Large Large</Large>
               <XLarge>X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large X-Large
               X-Large X-Large X-Large X-Large X-Large X-Large X-Large</XLarge>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Resizing textarea and scrolling.</p>
      <xf:textarea ref="Default">
         <xf:label>Default: </xf:label>
      </xf:textarea>
      <xf:textarea class="small-textarea" ref="Small">
         <xf:label>Small: </xf:label>
      </xf:textarea>
      <xf:textarea class="medium-textarea" ref="Medium">
         <xf:label>Medium: </xf:label>
      </xf:textarea>
      <xf:textarea class="large-textarea" ref="Large">
         <xf:label>Large: </xf:label>
      </xf:textarea>
      <xf:textarea class="x-large-textarea" ref="XLarge">
         <xf:label>X-Large: </xf:label>
      </xf:textarea>
   </body>
</html>

Style Sheet (textarea.css)[edit]

@namespace xf url("http://www.w3.org/2002/xforms");

/* put each textarea on its own row */
xf|textarea {
 display: table-row;
}

xf|textarea > xf|label {
   display: table-cell;
   font-family: sans-serif;
   font-size: 10pt;
   font-weight: bold;
   vertical-align: top;
   text-align: right;
   padding-right: 3px;
}

textarea {
   font-family: Courier, sans-serif;
}
.default-textarea
{
 font-style :regular;
}
.small-textarea textarea { 
   height: 4.4em; /* a bit less than four lines to demonstrate scrolling */
   width: 300px;
}

.medium-textarea textarea { 
   height: 6em;
   width: 400px;
}

.large-textarea textarea {
   font-family: Courier, sans-serif;
   height: 10em;
   width: 500px;
}

.x-large-textarea textarea {
   font-family: Courier, sans-serif;
   height: 20em;
   width: 700px;
}

Discussion[edit]

References[edit]

Next Page: Checkbox | Previous Page: Textarea

Home: XForms



Checkbox

Motivation[edit]

You have a boolean true/false value and want an input control to have a simple checkbox for a yes/no or true/false answer.

Method[edit]

We will use a standard input control but use the bind statement to bind the instance to a boolean datatype. We will do this in two ways, one using a bind without an ID and using the bind with an id so that we can reference the bind statement.

Note that checkboxes can also be demonstrated by using the xf:select control. But in that case a series of space-delimited values is stored in the value associated with the control.

Screen Image[edit]

Boolean Checkbox Using Input Control

Link to XForms Application[edit]

Load XForms Application

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <head>
      <title>XForms Checkbox Demo</title>
      <style type="text/css"><![CDATA[body {font-family: Helvetica, sans-serif;}]]>
      </style>
      <xf:model>
         <!-- load the module test data into the model -->
         <xf:instance xmlns="">
            <data>
               <bool1>true</bool1>
               <bool2>false</bool2>
            </data>
         </xf:instance>
         <!-- Here is where we indicate the datatypes of the instance variables -->
         <xf:bind ref="bool1" type="xs:boolean"  />
         <xf:bind id="bool2" ref="bool2" type="xs:boolean"  />
      </xf:model>
   </head>
   <body>
      <h1>XForms Checkbox Demo</h1>
      <xf:input ref="bool1">
         <xf:label>Bool 1: </xf:label>
      </xf:input>
      <br />
      <!-- use a named binding -->
      <xf:input bind="bool2">
         <xf:label>Bool 2: </xf:label>
      </xf:input>
      <br />
      <xf:output ref="bool1">
         <xf:label>Bool 1: </xf:label>
      </xf:output>
      <br />
      <xf:output bind="bool2">
         <xf:label>Bool 2: </xf:label>
      </xf:output>
   </body>
</html>

Next Page: Select1 | Previous Page: Textarea with style

Home: XForms



Select1

Motivation[edit]

You want an input control that allows a user to select one and only one item from a list of possible items. You have enough room on the form to display all the possible values. You would also like what the user sees and what is placed in the instance to be different.

Method[edit]

Any time you would like the user to make a single selection from a list of possible options you can use the XForms select1 control. There are two variations of this, one to display all the values (also known as a radio-button) and one that presents a drop-down list and thus takes up less screen area.

Each item on the list of possible choices must have an item and within that it must have a value and an optional label. The value is the string that will be inserted into the data element that is referenced using the ref property. The ref property points to a data element in your model.

Screen Image[edit]

XForms Select1 with appearance set to full

Link to Working XForms Example[edit]

Select1 Radio Buttons

Note that the lower-case value will be displayed under the select1 control to show you how the select1 control is changing the model. Only the labels are shown to the user.

Example Program[edit]

In the example below, the instance variable MyCode inside MyModel will be set to the value selected by the radio buttons control.

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>XForms Radio Button Usng Select1 appearance="full"</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <ColorCode/>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
       <p>XForms Radio Button Usng Select1 appearance="full"</p>
        <xf:select1 ref="ColorCode" appearance="full" >  
            <xf:item>
                <xf:label>Red</xf:label>
                <xf:value>red</xf:value> 
            </xf:item>
            <xf:item>
                <xf:label>Orange</xf:label>
                <xf:value>orange</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Yellow</xf:label>
                <xf:value>yellow</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Green</xf:label>
                <xf:value>green</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Blue</xf:label>
                <xf:value>blue</xf:value>
            </xf:item>
       </xf:select1>
       Output: <xf:output ref="ColorCode"/>
   </body>
</html>

Testing[edit]

You should see all the possible values when you use a full appearance. Each time you click on one of the radio buttons, the value of MyCode in the model will be updated and the output should automatically be updated. Note that the value is displayed (in lowercase), not the label.

Changing the Orientation to Horizontal[edit]

You can change the radio button to use a horizontal layout by applying float:left style to all the item elements.

Horizontal Radio Button

In your CSS do the following:

.horiz xf|item { 
  float: left; 
}

In your body wrap all of the xf:item elements in a div with a class="horiz"

<xf:select1 ref="my-element" appearance="full">
    <xf:label>Color: </xf:label>
    <div class="horiz">
      <xf:item>
          <xf:label>Red</xf:label>
          <xf:value>red</xf:value>
       </xf:item>
       <xf:item>
           <xf:label>Green</xf:label>
           <xf:value>green</xf:value>
       </xf:item>
       <xf:item>
           <xf:label>Red</xf:label>
           <xf:value>blue</xf:value>
       </xf:item>
     </div>
</xf:select1>

Discussion[edit]

You can always change a radio button to a drop down list by just removing the appearance="full" attribute from the select1 element.

You can also use an XPath expression to display labels and values from the model using the xf:itemset element.

<xf:select1 ref="my-element">
   <xf:itemset nodeset="instance('codes')/data/item">
      <xf:label ref="label"/>
      <xf:value ref="value"/>
   </xf:itemset>
</xf:select1>

See the other examples for examples of this.

Acknowledgments[edit]

The question about horizontal layout was posted on the mozilla.dev.tech.xforms mailing list in April of 2008 and the solution was provided by Aaron from IBM.

Next Page: Select1 drop list | Previous Page: Checkbox

Home: XForms



Select1 drop list

Motivation[edit]

You want to allow the user to select a single value from a list.

Method[edit]

Here is an example of using the select1 to create a drop-down list. The user must pick one and only one from the selected list.

Note that each item has a label (for humans to read) and a value (usually placed within an XML document). Values are typically stored in a database and use to compare to items together. Since values are frequently passed as arguments in a URL in a REST interface the convention is to only use lowercase letters and dashs. Do not put spaces, slashes and other characters in values if you are using REST interfaces. This makes the URLs difficult to read.

Screen Image[edit]

select1 control

Link to Working Application[edit]

Load XForms Application

Note that when the form is initially loaded, no day of the week is displayed in the input our output. After you press the drop-down list (the back triangle to the right of the input control) and select a day of the week the value will be filled in. A label (the name that starts with the uppercase) will be displayed in the select1 control. The actual version in the model will be the value which is the lower-case version. This is also the version that is displayed in the output.

Source Code[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
        <title>Demonstration of XForms Select1</title>
        <style type="text/css"><![CDATA[body {font-family: Helvetica, sans-serif;}]]></style>
        <xf:model>
            <xf:instance xmlns="">
                <data>
                    <DayOfWeekCode/>
                </data>
            </xf:instance>
        </xf:model>
    </head>
    <body>       
        <xf:select1 ref="DayOfWeekCode">  
            <xf:label>Day of Week:</xf:label>
                <xf:item>
                    <xf:label>Monday</xf:label>
                    <xf:value>monday</xf:value> 
                </xf:item>
                <xf:item>
                    <xf:label>Tuesday</xf:label>
                    <xf:value>tuesday</xf:value>
                </xf:item>
                <xf:item>
                    <xf:label>Wednesday</xf:label>
                    <xf:value>wednesday</xf:value>
                </xf:item>
                <xf:item>
                    <xf:label>Thursday</xf:label>
                    <xf:value>thursday</xf:value>
                </xf:item>
                <xf:item>
                    <xf:label>Friday</xf:label>
                    <xf:value>friday</xf:value>
                </xf:item>
                <xf:item>
                    <xf:label>Saturday</xf:label>
                    <xf:value>saturday</xf:value>
                </xf:item>
                <xf:item>
                    <xf:label>Sunday</xf:label>
                    <xf:value>sunday</xf:value>
                </xf:item>             
        </xf:select1>
        <br/>
        Output: <xf:output ref="DayOfWeekCode"/>
    </body>
</html>

Discussion[edit]

The list of values does not have to be in the body of the form. It can be in the model stored in an instance, it can be fetched on-demand from a web service. We will cover these in other examples.

Next Page: Open Selection | Previous Page: Select1

Home: XForms



Open Selection

Motivation[edit]

You want to have a control that suggests a set of values in a drop-down list but also allows a user to type in their own value.

Method[edit]

Just add the attribute selection="open" to your select1 control:

<xf:select1 ref="my-data" selection="open">

Screen Image[edit]

Select1 Control with selection attribute set to be open

Note that although a list of possible countries is listed, the user can type in any country that is not on this list.

XForms Application[edit]

Load XForms Application

The following example allows you to select a country code or enter your own country code:


<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>XForms Select1 Control Using Open Selection</title>
      <style type="text/css"><![CDATA[body {font-family: Helvetica, sans-serif;}]]></style>
        <xf:model>
            <xf:instance xmlns="">
                <data>
                    <CountryCode/>
                </data>
            </xf:instance>
        </xf:model>
   </head>
   <body>
      <p>XForms Select1 control using selection="open"</p>
      <xf:select1 ref="CountryCode" selection="open">
            <xf:label>Country:</xf:label>
            <xf:item>
                <xf:label>USA</xf:label>
                <xf:value>usa</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Canada</xf:label>
                <xf:value>can</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Japan</xf:label>
                <xf:value>jpn</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Mexico</xf:label>
                <xf:value>mex</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Other</xf:label>
                <xf:value>other</xf:value>
            </xf:item>
       </xf:select1>
       <br/>
       Output: <xf:output ref="CountryCode"/>
   </body>
</html>

Discussion[edit]

Very often you want to suggest values to the user to ensure consistency of data entry. The problem is that there are sometimes exceptions to a small list of items and the open selection control allows these exceptions to be entered.

One challenge of using this control is to let the user know they can enter an exception. You may have to add instructional text on the form such as "type value in this field if it does not appear on this list".


Next Page: Select | Previous Page: Select1 drop list

Home: XForms



Select

XForms Checkbox Buttons[edit]

There is just a small difference between using xf:select1 for radio buttons and the xf:select for multiple selection check boxes. In this example instead of round circles there are squares and you can check multiple squares. Note that the output contains a string with spaces between the values. This is why screen labels can have spaces but values should only contain dashes between the values.

Note that in this program we use appearance="full" attribute.

Screen Image[edit]

XForms select with multiple selections and appearance="full"

XForms Application[edit]

Load XForms Application

Note that as you select multiple items a space-delimited list of items appears in the output. This is a good example of why you do not want to put any spaces in a selection item value tag.

Sample Program[edit]

<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
>
   <head>
      <title>XForms Radio Button Using xf:Select appearance="full"</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <MyCode type="xs:string"/>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
       <p>XForms Radio Button Using Select appearance="full"</p>
        <xf:select ref="MyCode" selection="closed" appearance="full" >  
            <xf:item>
                <xf:label>Red</xf:label>
                <xf:value>red</xf:value> 
            </xf:item>
            <xf:item>
                <xf:label>Orange</xf:label>
                <xf:value>orange</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Yellow</xf:label>
                <xf:value>yellow</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Green</xf:label>
                <xf:value>green</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Blue</xf:label>
                <xf:value>blue</xf:value>
            </xf:item>
       </xf:select>
       Output: <xf:output ref="/data/MyCode"/>
   </body>
</html>

Using the Appearance Attribute[edit]

There are many ways to change the amount of screen area used to display a selection list with many items. The XForms specification suggests that the user can control this area using a simple attribute called appearance. The three suggested values of appearance are:

 appearance="full"
 appearance="compact"
 appearance="minimal"

Where:

  "full": all choices should be rendered at all times.
  "compact": a fixed number of choices should be rendered, with scrolling facilities as needed
  "minimal": a minimum number of choices should be rendered, with a facility to temporarily render additional choices

Many systems simply use a CSS style sheet to change this layout.

W3C Specification on the User Interface Options for Selecting Many

Testing[edit]

You should see the output change as you check different boxes. If you check multiple boxes, the result is a string with spaces separating the checked values.

Note that the XForms "value" in lowercase, not the "label", is inserted into the output string. This is an excellent example of why values should not contain spaces, just lowercase letters and dashes.


Next Page: Select Multi-Column | Previous Page: Open Selection

Home: XForms



Select Multi-Column

Motivation[edit]

Sometimes you have a large number of items to select from, for example you want to include one of many counties within a state to include in your search. In the following example there are 87 counties that might be included in a search. These county names are places in seven columns with 13 counties in all but the last column.

Screen Image[edit]

XForms-select-multi-column.jpg

Link to Working Example[edit]

Select Multi Column

Sample Program[edit]

Here is a sample program. Make sure to put the page into edit mode if you want to copy and paste the code. This is because Wiki software replaces the ampersand-lt-semicolon with a "&".

<html 
xmlns="http://www.w3.org/1999/xhtml" 
xmlns:xf="http://www.w3.org/2002/xforms" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Select County</title>
      <style type="text/css">
         @namespace xf url("http://www.w3.org/2002/xforms");
         body {
			 font-family: Helvetica, sans-serif;
			 font-size: 10pt;
         }
        .table-container {
			display: table-row;
         }
         .table-cell {
			display: table-cell;
			vertical-align: top;
         }
         xf|label {
			 font-weight: bold;
         }
      </style>
      <xf:model>
         <xf:instance xmlns="">
             <data>
                 <counties1>anoka carver</counties1>
                 <counties2>dakota</counties2>
                 <counties3>hennepin</counties3>
                 <counties4>mower</counties4>
                 <counties5>ramsey</counties5>
                 <counties6>scott</counties6>
                 <counties7>washington</counties7>
                 <counties />
              </data>
          </xf:instance>
      <xf:bind nodeset="counties"
               calculate="concat(../counties1, ' ', ../counties2, ' ',
               ../counties3, ' ', ../counties4,' ', ../counties5, ' ',
               ../counties6, ' ',../counties7)" />
      </xf:model>
      <xf:model id="code-tables">
         <xf:instance xmlns="" id="MNCountyCode" src="counties.xml" />
      </xf:model>
   </head>
   <body>
      <p>Select all counties to include in the search:</p>
         <div class="table-container ">
            <div class="table-cell">
               <xf:select ref="counties1" appearance="full">
                  <xf:itemset model="code-tables"
                          nodeset="instance('MNCountyCode')/EnumeratedValues/Item[boolean(position() &lt; 14)]">
                     <xf:label ref="Label" />
                     <xf:value ref="Value" />
                  </xf:itemset>
                </xf:select>
             </div>
             <div class="table-cell">
                <xf:select ref="counties2" appearance="full">
					<xf:itemset model="code-tables" nodeset="instance('MNCountyCode')/EnumeratedValues/Item[(position() &gt; 13) and (position() &lt; 27)]">
						<xf:label ref="Label" />
						<xf:value ref="Value" />
					</xf:itemset>
				</xf:select>
			</div>
			<div class="table-cell">
				<xf:select ref="counties3" appearance="full">
					<xf:itemset model="code-tables" nodeset="instance('MNCountyCode')/EnumeratedValues/Item[(position() &gt; 26) and (position() &lt; 40)]">
						<xf:label ref="Label" />
						<xf:value ref="Value" />
					</xf:itemset>
				</xf:select>
			</div>
			<div class="table-cell">
				<xf:select ref="counties4" appearance="full">
					<xf:itemset model="code-tables" nodeset="instance('MNCountyCode')/EnumeratedValues/Item[(position() &gt; 39) and (position() &lt; 53)]">
						<xf:label ref="Label" />
						<xf:value ref="Value" />
					</xf:itemset>
				</xf:select>
			</div>
			<div class="table-cell">
				<xf:select ref="counties5" appearance="full">
					<xf:itemset model="code-tables" nodeset="instance('MNCountyCode')/EnumeratedValues/Item[(position() &gt; 52) and (position() &lt; 66)]">
						<xf:label ref="Label" />
						<xf:value ref="Value" />
					</xf:itemset>
				</xf:select>
			</div>
			<div class="table-cell">
				<xf:select ref="counties6" appearance="full">
					<xf:itemset model="code-tables" nodeset="instance('MNCountyCode')/EnumeratedValues/Item[(position() &gt; 65) and (position() &lt; 79)]">
						<xf:label ref="Label" />
						<xf:value ref="Value" />
					</xf:itemset>
				</xf:select>
			</div>
			<div class="table-cell">
				<xf:select ref="counties7" appearance="full">
					<xf:itemset model="code-tables" nodeset="instance('MNCountyCode')/EnumeratedValues/Item[(position() &gt; 78)]">
						<xf:label ref="Label" />
						<xf:value ref="Value" />
					</xf:itemset>
				</xf:select>
			</div>
		</div>
		<xf:output ref="counties">
			<xf:label>Counties selected: </xf:label>
		</xf:output>
	</body>
</html>

Table for Data[edit]

The following is the shared resources file used by all the forms. Note that the values do not have any spaces in them. This way the codes can be passed through systems that use spaces as delimineters.

<CodeTable>
   <DataElementName>MNCountyCode</DataElementName>
   <EnumeratedValues>
      <Item>
         <Label>Aitkin</Label>
         <Value>aitkin</Value>
      </Item>
      <Item>
         <Label>Anoka</Label>
         <Value>anoka</Value>
      </Item>
      <Item>
         <Label>Becker</Label>
         <Value>becker</Value>
      </Item>
      <Item>
         <Label>Beltrami</Label>
         <Value>beltrami</Value>
      </Item>
      <Item>
         <Label>Benton</Label>
         <Value>benton</Value>
      </Item>
      <Item>
         <Label>Big Stone</Label>
         <Value>big-stone</Value>
      </Item>
      <Item>
         <Label>Blue Earth</Label>
         <Value>blue-earth</Value>
      </Item>
      <Item>
         <Label>Brown</Label>
         <Value>brown</Value>
      </Item>
      <Item>
         <Label>Carlton</Label>
         <Value>carlton</Value>
      </Item>
      <Item>
         <Label>Carver</Label>
         <Value>carver</Value>
      </Item>
      <Item>
         <Label>Cass</Label>
         <Value>cass</Value>
      </Item>
      <Item>
         <Label>Chippewa</Label>
         <Value>chippewa</Value>
      </Item>
      <Item>
         <Label>Chisago</Label>
         <Value>chisago</Value>
      </Item>
      <Item>
         <Label>Clay</Label>
         <Value>clay</Value>
      </Item>
      <Item>
         <Label>Clearwater</Label>
         <Value>clearwater</Value>
      </Item>
      <Item>
         <Label>Cook</Label>
         <Value>cook</Value>
      </Item>
      <Item>
         <Label>Cottonwood</Label>
         <Value>cottonwood</Value>
      </Item>
      <Item>
         <Label>Crow Wing</Label>
         <Value>crow-wing</Value>
      </Item>
      <Item>
         <Label>Dakota</Label>
         <Value>dakota</Value>
      </Item>
      <Item>
         <Label>Dodge</Label>
         <Value>dodge</Value>
      </Item>
      <Item>
         <Label>Douglas</Label>
         <Value>douglas</Value>
      </Item>
      <Item>
         <Label>Faribault</Label>
         <Value>faribault</Value>
      </Item>
      <Item>
         <Label>Fillmore</Label>
         <Value>fillmore</Value>
      </Item>
      <Item>
         <Label>Freeborn</Label>
         <Value>freeborn</Value>
      </Item>
      <Item>
         <Label>Goodhue</Label>
         <Value>goodhue</Value>
      </Item>
      <Item>
         <Label>Grant</Label>
         <Value>grant</Value>
      </Item>
      <Item>
         <Label>Hennepin</Label>
         <Value>hennepin</Value>
      </Item>
      <Item>
         <Label>Houston</Label>
         <Value>houston</Value>
      </Item>
      <Item>
         <Label>Hubbard</Label>
         <Value>hubbard</Value>
      </Item>
      <Item>
         <Label>Isanti</Label>
         <Value>isanti</Value>
      </Item>
      <Item>
         <Label>Itasca</Label>
         <Value>itasca</Value>
      </Item>
      <Item>
         <Label>Jackson</Label>
         <Value>jackson</Value>
      </Item>
      <Item>
         <Label>Kanabec</Label>
         <Value>kanabec</Value>
      </Item>
      <Item>
         <Label>Kandiyohi</Label>
         <Value>kandiyohi</Value>
      </Item>
      <Item>
         <Label>Kittson</Label>
         <Value>kittson</Value>
      </Item>
      <Item>
         <Label>Koochiching</Label>
         <Value>koochiching</Value>
      </Item>
      <Item>
         <Label>Lac Qui Parle</Label>
         <Value>lac-qui-parle</Value>
      </Item>
      <Item>
         <Label>Lake</Label>
         <Value>lake</Value>
      </Item>
      <Item>
         <Label>Lake of the Woods</Label>
         <Value>lake-of-the-woods</Value>
      </Item>
      <Item>
         <Label>Lesueur</Label>
         <Value>lesueur</Value>
      </Item>
      <Item>
         <Label>Lincoln</Label>
         <Value>lincoln</Value>
      </Item>
      <Item>
         <Label>Lyon</Label>
         <Value>lyon</Value>
      </Item>
      <Item>
         <Label>Mahnomen</Label>
         <Value>mahnomen</Value>
      </Item>
      <Item>
         <Label>Marshall</Label>
         <Value>marshall</Value>
      </Item>
      <Item>
         <Label>Martin</Label>
         <Value>martin</Value>
      </Item>
      <Item>
         <Label>McLeod</Label>
         <Value>mcleod</Value>
      </Item>
      <Item>
         <Label>Meeker</Label>
         <Value>meeker</Value>
      </Item>
      <Item>
         <Label>Mille Lacs</Label>
         <Value>mille-lacs</Value>
      </Item>
      <Item>
         <Label>Morrison</Label>
         <Value>morrison</Value>
      </Item>
      <Item>
         <Label>Mower</Label>
         <Value>mower</Value>
      </Item>
      <Item>
         <Label>Murray</Label>
         <Value>murray</Value>
      </Item>
      <Item>
         <Label>Nicollet</Label>
         <Value>nicollet</Value>
      </Item>
      <Item>
         <Label>Nobles</Label>
         <Value>nobles</Value>
      </Item>
      <Item>
         <Label>Norman</Label>
         <Value>norman</Value>
      </Item>
      <Item>
         <Label>Olmsted</Label>
         <Value>olmsted</Value>
      </Item>
      <Item>
         <Label>Otter Tail</Label>
         <Value>otter-tail</Value>
      </Item>
      <Item>
         <Label>Pennington</Label>
         <Value>pennington</Value>
      </Item>
      <Item>
         <Label>Pine</Label>
         <Value>pine</Value>
      </Item>
      <Item>
         <Label>Pipestone</Label>
         <Value>pipestone</Value>
      </Item>
      <Item>
         <Label>Polk</Label>
         <Value>polk</Value>
      </Item>
      <Item>
         <Label>Pope</Label>
         <Value>pope</Value>
      </Item>
      <Item>
         <Label>Ramsey</Label>
         <Value>ramsey</Value>
      </Item>
      <Item>
         <Label>Red Lake</Label>
         <Value>red-lake</Value>
      </Item>
      <Item>
         <Label>Redwood</Label>
         <Value>redwood</Value>
      </Item>
      <Item>
         <Label>Renville</Label>
         <Value>renville</Value>
      </Item>
      <Item>
         <Label>Rice</Label>
         <Value>rice</Value>
      </Item>
      <Item>
         <Label>Rock</Label>
         <Value>rock</Value>
      </Item>
      <Item>
         <Label>Roseau</Label>
         <Value>roseau</Value>
      </Item>
      <Item>
         <Label>Saint Louis</Label>
         <Value>saint-louis</Value>
      </Item>
      <Item>
         <Label>Scott</Label>
         <Value>scott</Value>
      </Item>
      <Item>
         <Label>Sherburne</Label>
         <Value>sherburne</Value>
      </Item>
      <Item>
         <Label>Sibley</Label>
         <Value>sibley</Value>
      </Item>
      <Item>
         <Label>Stearns</Label>
         <Value>stearns</Value>
      </Item>
      <Item>
         <Label>Steele</Label>
         <Value>steele</Value>
      </Item>
      <Item>
         <Label>Stevens</Label>
         <Value>stevens</Value>
      </Item>
      <Item>
         <Label>Swift</Label>
         <Value>swift</Value>
      </Item>
      <Item>
         <Label>Todd</Label>
         <Value>todd</Value>
      </Item>
      <Item>
         <Label>Traverse</Label>
         <Value>traverse</Value>
      </Item>
      <Item>
         <Label>Wabasha</Label>
         <Value>wabasha</Value>
      </Item>
      <Item>
         <Label>Wadena</Label>
         <Value>wadena</Value>
      </Item>
      <Item>
         <Label>Waseca</Label>
         <Value>waseca</Value>
      </Item>
      <Item>
         <Label>Washington</Label>
         <Value>washington</Value>
      </Item>
      <Item>
         <Label>Watonwan</Label>
         <Value>watonwan</Value>
      </Item>
      <Item>
         <Label>Wilkin</Label>
         <Value>wilkin</Value>
      </Item>
      <Item>
         <Label>Winona</Label>
         <Value>winona</Value>
      </Item>
      <Item>
         <Label>Wright</Label>
         <Value>wright</Value>
      </Item>
      <Item>
         <Label>Yellow Medicine</Label>
         <Value>yellow-medicine</Value>
      </Item>
   </EnumeratedValues>
</CodeTable>

Discussion[edit]

The ideal way to do this would be to use a style sheet to pour the items into different cells of a table. Unfortunately there is little documentation on how the itemset results can be styled into different tables.

Next Page: Select1 Multi-Column | Previous Page: Select

Home: XForms



Select1 Multi-Column

Motivation[edit]

You want to select one item from multiple column of items.

Method[edit]

To do this we must unselect all of the column not selected so that only one column has a value in the output.

Source Code[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
        <title>Select1 Multi Column</title>
        
        <style type="text/css"><![CDATA[
            @namespace xf url("http://www.w3.org/2002/xforms");
            body {
            font-family: Helvetica, sans-serif;
            font-size: 10pt;
            }
            
            /* vertical align the selectors in each column.  I am not sure why none of these CSS selectors work */
            .state-selector tr td {
            vertical-align:text-top;
            align: top;
            valign: top;
            }
            
            /* this is also not working */
            .state-selector xf\:label {
            font-weight: bold;
            }
]]>
        </style>
        
        <xf:model>
            <xf:instance xmlns="" id="cols">
                <data>
                    <col-1/>
                    <col-2/>
                    <col-3/>
                    <cols/>
                </data>
            </xf:instance>
            
            <!-- this concatenates the three column values -->
            <xf:bind nodeset="cols" calculate="concat(../col-1, ../col-2,  ../col-3)"/>
            
            <!-- this is where we log the events -->
            <xf:instance id="log">
                <data xmlns="">
                    <event/>
                </data>
            </xf:instance>
            
            <xf:action ev:event="xforms-ready">
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'xforms-ready'"/>
            </xf:action>
            
                   
        </xf:model>
    </head>
    <body>
        <p>Select1 Multi Column</p>
        <table border="1">
            <tr>
                <td valign="top">
                    <xf:select1 ref="col-1" appearance="full">
                        <xf:item>
                            <xf:label>Red</xf:label>
                            <xf:value>red</xf:value>
                        </xf:item>
                        <xf:item>
                            <xf:label>Orange</xf:label>
                            <xf:value>orange</xf:value>
                        </xf:item>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue ref="instance('cols')/col-2" value="''"/>
                            <xf:setvalue ref="instance('cols')/col-3" value="''"/>
                            <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                            <xf:setvalue ref="instance('log')/event[last()]" value="'col 1 xforms-value-changed'"/>
                        </xf:action>
                    </xf:select1>
                </td>
                <td valign="top">
                    <xf:select1 ref="col-2" appearance="full">
                        <xf:item>
                            <xf:label>Yellow</xf:label>
                            <xf:value>yellow</xf:value>
                        </xf:item>
                        <xf:item>
                            <xf:label>Green</xf:label>
                            <xf:value>green</xf:value>
                        </xf:item>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue ref="instance('cols')/col-1" value="''"/>
                            <xf:setvalue ref="instance('cols')/col-3" value="''"/>
                            <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                            <xf:setvalue ref="instance('log')/event[last()]" value="'col 2 xforms-value-changed'"/>
                        </xf:action>
                    </xf:select1>
                </td>
                <td valign="top">
                    <xf:select1 ref="col-3" appearance="full">
                        <xf:item>
                            <xf:label>Blue</xf:label>
                            <xf:value>blue</xf:value>
                        </xf:item>
                        <xf:item>
                            <xf:label>Indigo</xf:label>
                            <xf:value>indigo</xf:value>
                        </xf:item>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue ref="instance('cols')/col-1" value="''"/>
                            <xf:setvalue ref="instance('cols')/col-2" value="''"/>
                            <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                            <xf:setvalue ref="instance('log')/event[last()]" value="'col 3 xforms-value-changed'"/>
                        </xf:action>
                    </xf:select1>
                </td>
            </tr>
        </table>
        
        <xf:trigger>
            <xf:label>Clear</xf:label>
            <xf:action ev:event="DOMActivate">
                <xf:setvalue ref="col-1" value="''"/>
                <xf:setvalue ref="col-2" value="''"/>
                <xf:setvalue ref="col-3" value="''"/>
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'clear'"/>
            </xf:action>
        </xf:trigger>
        <br/>
        
        <xf:trigger>
            <xf:label>refresh</xf:label>
            <xf:action ev:event="refresh">
                <xf:setvalue ref="col-1" value="''"/>
                <xf:setvalue ref="col-2" value="''"/>
                <xf:setvalue ref="col-3" value="''"/>
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'refresh'"/>
            </xf:action>
        </xf:trigger>
        <br/>
        
        <xf:output ref="cols">
            <xf:label>Color selected: </xf:label>
        </xf:output>
        <br/>
        <xf:output ref="col-1">
            <xf:label>Collumn 1: </xf:label>
        </xf:output>
        <br/>
        <xf:output ref="col-2">
            <xf:label>Collumn 2: </xf:label>
        </xf:output>
        <br/>
        <xf:output ref="col-3">
            <xf:label>Collumn 3: </xf:label>
        </xf:output>
        <br/>
        <div id="log">
            <span>
                <b>Event Log</b>
            </span>
            <xf:repeat id="results-repeat" nodeset="instance('log')/event">
                <xf:output ref="."/>
            </xf:repeat>
        </div>
    </body>
</html>


Next Page: Selecting from Model | Previous Page: Select Multi-Column

Home: XForms



Selecting from Model

Motivation[edit]

You want to store lists in the model, not in the user interface. This allows a list to be used many places in a form and also enables lists to be read from external files (see the next example).

Screen Image[edit]

XForms-select-from-model.jpg

Execute Sample XForms Application[edit]

Load XForms Application

Sample Program[edit]

This example shows how to use the XForms itemset element to get data from the selection list directly from the model. Note that itemset is very similar to the group command in syntax: the outer loop tells you where to get your data and the inner loop binds a data element to a form value or item.

<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
        <title>Getting Selection List Data From the XForms Model</title>
        <style type="text/css"><![CDATA[
            body {font-family: Helvetica, Verdanan, sans-serif;}
        ]]>
        </style>
        <xf:model>

            <!-- this instance holds the data you send to the server on save -->
            <xf:instance id="my-item" xmlns="">
                <data>
                    <!-- the default color is red -->
                    <ItemColorCode>red</ItemColorCode>
                </data>
            </xf:instance>

            <!-- this instance holds the code tables used for all selection lists -->
            <xf:instance id="code-tables" xmlns="">
                <code-tables>
                    <code-table>
                        <code-table-id>ItemColorCode</code-table-id>
                        <item>
                            <label>Red</label>
                            <value>red</value>
                        </item>
                        <item>
                            <label>Orange</label>
                            <value>orange</value>
                        </item>
                        <item>
                            <label>Yellow</label>
                            <value>yellow</value>
                        </item>
                        <item>
                            <label>Green</label>
                            <value>green</value>
                        </item>
                        <item>
                            <label>Blue</label>
                            <value>blue</value>
                        </item>
                    </code-table>
                </code-tables>
            </xf:instance>
        </xf:model>
    </head>
    <body>
        <h1>Getting Selection List Data From the XForms Model</h1>
        <xf:select ref="ItemColorCode" appearance="full">
            <xf:itemset
                nodeset="instance('code-tables')/code-table[code-table-id='ItemColorCode']/item">
                <xf:label ref="label"/>
                <xf:value ref="value"/>
            </xf:itemset>
        </xf:select>
        <br/> Output: <xf:output ref="ItemColorCode"/>
    </body>
</html>

Discussion[edit]

This is a much more flexible way to manage lists. The instance document may be fetched dynamically from a remote database and the form does not need to be updated when lists change.


Next Page: Selecting from File | Previous Page: Select1 Multi-Column

Home: XForms



Selecting from File

Best Practice

Motivation[edit]

People who design forms frequently have to maintain many code tables. These code tables may change frequently and there may be processes that update a database of centrally maintained code tables. So you want each form to dynamically get the current relevant codes from an XML file or a RESTful web service.

This sample program demonstrates how to read a list of codes with labels directly from a file or code-table web service. In this example the file that contains the codes is just a well-formed XML file in the same directory that the form is located in.

Loading XML instance data from a local file or web service[edit]

The following code fragment, usually in the HTML head, demonstrates how to read XML data from a local file in the same directory as the form by using the "src" attribute of the instance.

Loading a Single Codes Table into a Single Instance[edit]

<html>
   <xf:model>
      <xf:instance src="XMLSchemaTypeCode.xml" id="XMLSchemaTypeCode"/>
   </xf:model>
</html>

Loading Codes from a Web Service[edit]

It is common to have a single web service load all code tables. This service can be passed parameters such as the name of the code table as well as the group the person is a part of. This can narrow down the list of selections for long lists.

<html>
   <xf:model>
      <xf:instance id="ApprovalCodes" src="/db/mdr/services/all-codes.xq?code=ApprovalCodes&group=editor"/>
   </xf:model>
</html>

Loading all Codes into a single Instance[edit]

The problem with loading individual code tables into individual instances is that you must perform a separate HTTP get for each code table. This is not a problem for forms with one or two small selection lists. But for large forms with many selection lists this can slow down form response time. The solution is to load all codes into a single instance with a single HTTP GET request. Each code table can then be selected from this instance.

<html>
   <xf:model>
      <xf:instance id="code-tables" src="/db/mdr/services/all-codes.xq?form=DataElementManager&group=admin"/>
   </xf:model>
</html>

In this second example all the codes in the entire form are generated by a service of the Metadata Registry (MDR). The data returned by this server is a collection of codes for each select1 control in the form.

This will look for a well-formed XML file in the current directory and load it into the model instance.

Note that in this case the model is given an id. This is necessary to allow multiple code tables to each be read into their own separate model.

Screen Image[edit]

Here is a screen image of the program. As the user selects from the drop-down list, the value of the output is immediately updated.

XForms-select-from-file.jpg

Note that label on the screen is not the same as the label stored in the model.

Sample Program[edit]

<html
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xf="http://www.w3.org/2002/xforms" >
   <head>
      <title>Select List From File</title>
      
      /* the default model */
      <xf:model>
         <xf:instance id="save-data" xmlns="">
            <data>
                  <MyXMLSchemaTypeCode/>
            </data>
         </xf:instance>
         <xf:instance id="code-tables" src="XMLSchemaTypeCode.xml"/>
      </xf:model>
      
   </head>
   <body>
      <p>This selection list was read from a file.</p>
      <xf:select1  ref="/MyData/MyXMLSchemaTypeCode">
         <xf:label>Select XML Schema data type: </xf:label>
         <xf:itemset ref="instance('code-tables')/XMLSchemaTypeCode/item">
            <xf:label ref="label"/>
            <xf:value ref="value"/>
         </xf:itemset>
      </xf:select1>
      <br/>
      <xf:output ref="instance('save-data')/MyXMLSchemaTypeCode">
         <xf:label>Value of MyXMLSchemaTypeCode: </xf:label>
      </xf:output>
   </body>
</html>

Sample XML Data[edit]

<?xml version="1.0" encoding="UTF-8"?>
<XMLSchemaTypeCode>
   <label>XML Schema Type:</label>
   <item>
      <label>Date and Time</label>
      <value>dateTime</value>
   </item>
   <item>
      <label>Time (HH:MM:SS-06:00)</label>
      <value>time</value>
   </item>
   <item>
      <label>Date (yyyy-mm-dd)</label>
      <value>date</value>
   </item>
   <item>
      <label>Year and Month</label>
      <value>gYearMonth</value>
   </item>
   <item>
      <label>Year (nnnn)</label>
      <value>gYear</value>
   </item>
   <item>
      <label>Month and Day</label>
      <value>gMonthDay</value>
   </item>
   <item>
      <label>Day of Month (1 .. 31)</label>
      <value>gDay</value>
   </item>
   <item>
      <label>Month (1 .. 12)</label>
      <value>gMonth</value>
   </item>
   <item>
      <label>String</label>
      <value>string</value>
   </item>
   <item>
      <label>Boolean (true/false)</label>
      <value>boolean</value>
   </item>
   <item>
      <label>Base 64 Binary</label>
      <value>base64Binary</value>
   </item>
   <item>
      <label>Decimal (0.00)</label>
      <value>decimal</value>
   </item>
   <item>
      <label>Any URI</label>
      <value>anyURI</value>
   </item>
   <item>
      <label>Integer (...,-2,-1,0,1,2,...)</label>
      <value>integer</value>
   </item>
   <item>
      <label>Non-Positive Integer (...,-2,-1,0)</label>
      <value>nonPositiveInteger</value>
   </item>
   <item>
      <label>Negative Integer (...,-2,-1)</label>
      <value>negativeInteger</value>
   </item>
   <item>
      <label>Long (-9,223,372T .. 9,223,372T)</label>
      <value>long</value>
   </item>
   <item>
      <label>Int (-2,147,483,648 .. 2,147,483,647)</label>
      <value>int</value>
   </item>
   <item>
      <label>Short (-32,768 .. 32,767)</label>
      <value>short</value>
   </item>
   <item>
      <label>Byte (-128 .. 127)</label>
      <value>byte</value>
   </item>
   <item>
      <label>Non-negative Integer (0..N)</label>
      <value>nonNegativeInteger</value>
   </item>
    <item>
      <label>Positive Integer (1..N)</label>
      <value>positiveInteger</value>
   </item>
   <item>
      <label>Unsigned Long (0 .. 18,446,744T)</label>
      <value>unsignedLong</value>
   </item>
   <item>
      <label>Unsigned Int (0 .. 4,294,967,295)</label>
      <value>unsignedInt</value>
   </item>
   <item>
      <label>Unsigned Short (0.. 65,535)</label>
      <value>unsignedShort</value>
   </item>
   <item>
      <label>Unsigned Byte (0..255)</label>
      <value>unsignedByte</value>
   </item>
</XMLSchemaTypeCode>

Note that to be well-formed the XML file MUST contain a root data element that must match the node-set argument.

Extracting data from an XML REST web service[edit]

You can replace the instance src attribute with a path directly to a XML REST web service. For example, if you put all your code tables into a project resources collection the path would look like the following:

<xf:instance src="../resources/code-tables/PersonGenderCode.xml"/>

or if your system codes are stored in a single XML file and you have a wrapper XQuery

<xf:instance src="../resources/code-tables/get-codes-for.xq?element=PersonGenderCode"/>

Selection Lists From A Single Instance[edit]

To keep your forms fast, it is usually better to do a single HTTP GET operation for all your codes. Forms that have many selection lists will take a long time to load if each list does a separate HTTP GET operation. For large forms it is easy to get a 10x speedup in form load times.

Structure of Code Tables Instance[edit]

The following is a sample structure of all codes loaded into a single instance:

<xf:instance id="code-tables">
   <code-tables>
      <code-table>
         <code-table-name>MyElementCode</code-table-name>
         <items>
            <item>
               <label>Joe Smith</label>
               <value>42</value>
            </item>
            <item>
               <label>Sue Johnson</label>
               <value>47</value>
            </item>
         <items>
      </code-table>
      <code-table>
         <code-table-name>ColorCode</code-table-name>
         <items>
            <item>
               <label>Red</label>
               <value>1</value>
            </item>
            <item>
               <label>Orange</label>
               <value>2</value>
            </item>
         <items>
      </code-table>
   </code-tables>
</xf:instance>

Sample Select1[edit]

Once your data is loaded into your model, each of your select1 or select controls can get its data directly from the model using the xf:itemset element. Itemset works just like repeat and uses nodeset (not ref) to get all its values. Here is an example of how to get the itemset data from your code-tables instance.

<xf:select1 ref="instance('save-data')/MyElementName">
   <xf:label>My Element:</xf:label>
   <xf:itemset nodeset="instance('code-tables')/code-table[code-table-name='MyElementCode']/items/item">
       <xf:label ref="label"/>
       <xf:value ref="value"/>
   </xf:itemset>
</xf:select1>

Note that the predicate [code-table-name='MyElementCode'] will only put the items for that code into the selection list.

Auto Generation of Code Tables from Metadata Registry[edit]

Because XML Schema does not contain information for presentation we use the following workflow as a "best practice".

  1. Store all label/value pairs in external code table files or get this information from a web service.
  2. For each form, create a web service that will generate a code-tables element for all the codes used in that form.
  3. Load the code-tables element into a separate instance in your model with an id of "code-tables".
  4. Select the code table out of that instance for each select1 or select element by getting a code table with that name.

Discussion[edit]

When a group of complex forms that share common codes needs to be placed in their own directory and yet still link to a central directory of codes, you can also use relative code table linking. For example a sibling directory could be called "code-tables" and the src="MyCode.xml" statement could be modified to be src="../code-tables/MyCode.xml".

If you have an XML Schema for the form you can also extract a list of all enumerations for each simpleType. This list of codes can then be passed to a web service that creates a list of all the codes in your registry. This allows the form to automatically be updated when new codes are added to the XML Schema.

If you have a RESTful web service that contains all the codes for a form, you can replace this web service URI for the XML file.

Next Page: Selecting a Date | Previous Page: Selecting from Model

Home: XForms



Selecting a Date

Motivation[edit]

Users frequently want to select a date rather than have to type the date into a field. They often want to select a date such as "next Tuesday", but they might have to use a calendar to look up the day that Tuesday falls on.

Luckily a calendar selector is built in to most XForms implementations.

Screen Image[edit]

If you have a field that is "bound" to a date type the form will appear as follows:

XForms-date-select.jpg

Link to Working XForms Application[edit]

Date Selector

Sample Program[edit]

Here is an example that uses the date picker:


<html 
xmlns="http://www.w3.org/1999/xhtml" 
xmlns:xf="http://www.w3.org/2002/xforms" 
xmlns:ev="http://www.w3.org/2001/xml-events" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <head>
      <title>Example using a date selector by binding an instance to an XML Schema date type</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <MyDate />
            </data>
         </xf:instance>
         <xf:bind nodeset="MyDate" type="xs:date" />
      </xf:model>
   </head>
   <body>
      <p>Example of using the date selector by binding an instance to an XML Schema date type:
		<br />
         <xf:input ref="MyDate">
            <xf:label>Enter a date: </xf:label>
         </xf:input>
      </p>
   </body>
</html>

Testing[edit]

A small calendar icon should appear directly to the right of the input field. Click on the calandar icon and select a date. Note that you can change the day and the month using the calendar picker.

Discussion[edit]

The key line is:

  <xf:bind nodeset="MyDate" type="xs:date" />

Note that if you do not use the bind command, the input will work like an ordinary text field.

The format that is put into the date field is YYYY-MM-DD which is the format used in XML for dates. You can use other formats such as MM-DD-YYYY but you will have to use an XPath expression to format the appearance of the field and make the appearance separate from the value in the model.

Once bound to type "xs:date", an empty string(date not set) will not allow the form to submit, there is no known direct solution, however using custom binding this can be overcome

example:

  <xf:input ref="Date" appearance="date" />


css:

   @namespace xf url(http://www.w3.org/2002/xforms);
   @namespace mozType url(http://www.mozilla.org/projects/xforms/2005/type);
   xf|input[appearance="date"] {    
   -moz-binding: url('chrome://xforms/content/input-xhtml.xml#xformswidget-input-date');  
   }
   xf|input[appearance="date"] span[mozType|calendar] { 
   -moz-binding: url('chrome://xforms/content/widgets-xhtml.xml#calendar-full'); 
   z-index: 2147481647;   
   }


Next Page: Formatting a date | Previous Page: Selecting from File

Home: XForms



Formatting a date

Motivation[edit]

XML stores dates in the format YYYY-MM-DD such as 2007-08-30. Unfortunately this is usually not the way users want to view their dates.

This example XForms program uses CSS to hide an input date and an XPath expression to get the date to display in the MM/DD/YYYY format typically used in the US.

Screen Image[edit]

Date selector before calendar icon selected.
Date selector after calendar icon selected.

Link to XForm Example[edit]

Link to Date Format External Example

Sample Program[edit]

<html
  xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:d="http://www.mydata.com/xmlns/data">
    <head>
        <title>Demo of date formatting using XPath concat and substring.</title>
        <style type="text/css"><![CDATA[
    @namespace xf url('http://www.w3.org/2002/xforms');
    
    .hidden .xf-value {
       display:none;
    }
]]>
      </style>
   
       <xf:model>
          <xf:instance xmlns="">
             <MyModel>
               <MyDate>2006-09-12</MyDate>
             </MyModel>
          </xf:instance>
          <xf:bind nodeset="/MyModel/MyDate" type="xs:date" />
       </xf:model>
   </head>
   <body>
        <xf:input class="hidden" ref="/MyModel/MyDate" incremental="true">
            <xf:label>Select Date: </xf:label>
        </xf:input>
        <!-- get the month (two characters wide starting at character number 6), then the day then the year -->
        <xf:output           
            value="concat(substring(/MyModel/MyDate,6,2),
            '/',
            substring(/MyModel/MyDate,9,2),
            '/',
            substring(/MyModel/MyDate,1,4))"
        />
    </body>
</html>

Discussion[edit]

The CSS style sheet hides the input field. The input has the class="hidden" attribute.

The output is formatted using the following XPath expression:

concat(
   substring(/MyModel/MyDate,6,2),
   '/',
   substring(/MyModel/MyDate,9,2),
   '/',
   substring(/MyModel/MyDate,1,4)
)

Concat is the XPath concatenation operator. The input is in the format: "YYYY-MM-DD". We just need to reach in and get the correct characters out.

  1. The first substring goes to the 6th characer and pulls out the two month (MM) characters.
  2. The second substring starts at the 9th character and gets two day (DD) characters.
  3. The last substring returns characters 1-4 which are the four year characters (YYYY).

You do not have to display all four letters in the year. By changing the last substring from:

substring(/MyModel/MyDate,1,4)

to be

substring(/MyModel/MyDate,3,4)

You will only get the last two digits of the year.


Next Page: Upload | Previous Page: Selecting a Date

Home: XForms



Upload

Motivation[edit]

The upload element allows you to select a file from the file system using your operating system's "Browse" user interface. This file can then be transferred to the file server that the web form resides.

Screen Image[edit]

Here is a screen image of the Firefox XForms extension upload control after the C:\tmp\Foo.xml file was selected:

XForms-upload.jpg

The XForms upload Element[edit]

<xf:upload ref="XPathExpression" mediatype="text/xml">
  <xf:filename ref="XPathExpression" />
  <xf:mediatype ref="XPathExpression" />
</xf:upload>

Sample Program[edit]

This sample program has a single instance variable called "File". At the end of the select this variable is set to the path-name of the file you just selected.

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
   <head>
       <title/>
       <xf:model>
           <xf:instance xmlns="">
               <Data>
                   <File xsi:type="xs:anyURI"/>
               </Data>
           </xf:instance>
       </xf:model>
   </head>
   <body>
       <xf:upload ref="/Data/File">
           <xf:filename>file:///C:/tmp/*.xml</xf:filename>
           <xf:mediatype>text/xml</xf:mediatype>
       </xf:upload>
       <br/>
       <xf:output ref="/Data/File">
          <xf:label>File: </xf:label>
       </xf:output>
   </body>
</html>

Discussion[edit]

At the time of this writing, there is little documentation on how the upload control works. The screen shot above was taken from the Firefox XForms 0.8 running on Firefox 3 implementation. Note that the file name appears twice in the control itself. This may not be the future behavior. This may be that the filename and mediatype text inside the control are being displayed. There is no documentation yet on how to disable the clear trigger.

There is not yet documentation on how to upload instance data into the model using the upload control. Right now instance data must be hard-coded into the src attribute of an instance.

The following loads both an image and a URI.

<html xmlns="http://www.w3.org/1999/xhtml" 
xmlns:ev="http://www.w3.org/2001/xml-events" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:xf="http://www.w3.org/2002/xforms" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <head>
        <title/>
        <xf:model>
            <xf:instance xmlns="">
                <data>
                    <image xsi:type="xs:base64Binary"/>
                    <uri xsi:type="xs:anyURI"/>
                </data>
            </xf:instance>
            <xf:submission id="save" action="http://xformstest.org/cgi-bin/showinstance.sh" method="post"/>
        </xf:model>
    </head>
    <body>
        <xf:upload ref="image">
            <xf:label>Upload Photo:</xf:label>
        </xf:upload>
        <br/>
        <xf:upload ref="uri">
            <xf:label>Upload File:</xf:label>
            <xf:filename>file:///C:/tmp/*.xml</xf:filename>
            <xf:mediatype>text/xml</xf:mediatype>
        </xf:upload>
        <br/>
        <xf:output ref="image">
            <xf:label>image: </xf:label>
        </xf:output>
        <br/>
        <xf:output ref="uri">
            <xf:label>uri: </xf:label>
        </xf:output>
        <br/>
        <xf:submit submission="save">
            <xf:label>Save</xf:label>
        </xf:submit>
    </body>
</html>

Uploading Binary Files[edit]

Any file type such as an image or XML file can be converted to a 64bit encoded file, stored in the instance and then transmitted to the server inside of a POST. On the server the file can be converted back to a string or binary.

Sample Echo With Binary to String Unencoding[edit]

The following is a simple echo script written in XQuery that echos back the binary file in XML. It is an XQuery script that uses a binary-to-string conversion function. This takes a file of type xs:base64binary and returns a string representation of the file. The data to be returned is in the element with the element name "xml-base64".

   xquery version "1.0";
   declare option exist:serialize "method=xml media-type=text/xml indent=yes"; 

   (: this gets the data from the HTTP POST :)
   let $post-data := request:get-data()
(: this converts the base-64 binary to a plaintext string that holds the unparsed XML content :)
   let $xml-as-string := util:base64-decode($post-data//xml-base64)
   let $parsed-xml := util:parse($xml-as-string)

   return
   <results>
      <xml-as-string>{$xml-as-string}</xml-as-string>
      <parsed-xml>{$parsed-xml}</parsed-xml>
   </results>

Sample Form[edit]

<html 
    xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    >
    <head>
        <title>Upload XML</title>
        <xf:model>
            <xf:instance xmlns=''>
                <data>
                    <xml-base64 xsi:type="xs:base64Binary"/>
                </data>
            </xf:instance>
            
            <xf:submission id='post-to-echo' 
                action='echo-base64-binary.xq' replace="all"
                method='post'/>
            
        </xf:model>
    </head>
    <body>
        <br/>
        
        <xf:upload ref="xml-base64">
            <xf:label>Upload XML File:</xf:label>
        </xf:upload>
        
        <br/>
        <xf:output ref="xml-base64">
            <xf:label>XML file encoded in base64binary: </xf:label>
        </xf:output>
        <br/>
        
        <xf:submit submission="post-to-echo">
            <xf:label>Post to Echo</xf:label>
        </xf:submit>
        
    </body>
</html>

Sample File[edit]

<test>This is a small XML file.</test>

Warnings[edit]

The attribute data type assignment xsi:type="xs:anyURI" must be associated with the variable used to store the file path name.

References[edit]


Next Page: Trigger | Previous Page: Formatting a date

Home: XForms



Trigger

Motivation[edit]

XForms creates a general way to represent a button that will work on web pages and cell phones. But it is not called "button" as in most other systems. It is an abstraction or generalization of a button called a trigger. A trigger is an abstraction of a web button or another event such as a button on a cell phone. Using a trigger abstraction allows your XForms to be more portable.

Screen Image[edit]

A simple XForm button and the resulting message

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms"
 xmlns:ev="http://www.w3.org/2001/xml-events"
>
   <head>
      <title>Button Example</title>
      <xf:model>
         <xf:instance xmlns="">
             <data/>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <xf:trigger>
          <xf:label>Button</xf:label>
          <xf:hint>If you press this you will get a hello world message.</xf:hint>
          <xf:message level="modal" ev:event="DOMActivate">Hello World!</xf:message>
      </xf:trigger>
   </body>
</html>

Discussion[edit]

This example has both a label and a hint. XForms also has help text that can be used but the way help is implemented is implementation specific.

Styling a Trigger[edit]

By default each trigger looks like an HTML button. You can turn this off by setting appearance="minimal".

<xf:trigger appearance="minimal">
   <xf:label>Save</xf:label>
</xf:trigger>

Having a Button Trigger Multiple Events[edit]

When you press on a button (trigger) you sometimes want the trigger to do more than a single submission. Whenever you want to do this you can just add an action element and wrap multiple sends in the action:

<xf:trigger>
   <xf:label>Submit</xf:label>    
   <xf:action ev:event="DOMActivate">
      <xf:send submission="getTime"/>
      <xf:send submission="getTemperature"/>
    </xf:action>
</xf:trigger>

References[edit]

W3C trigger element

FireFox CSS styling hints

Next Page: Controlling Button Appearance | Previous Page: Upload

Home: XForms



Controlling Button Appearance

This example demonstrates how to control the button appearance using labels, hint text and images. To see the button images appear you will need to create a file called XForms-button.jpg in the folder that this program is executed from.

This example requires an image to be used in the program.

This image can be downloaded from here: XForms-button image.jpg.

Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>XForms Trigger Appearances</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <label>Label text from the model</label>
               <message>Message text from the model</message>
               <hint>Hint text from the model</hint>
            </data>
         </xf:instance>
         <xf:submission method="post" id="submission" />
      </xf:model>
   </head>
   <body>
      <h1>Test of Trigger Appearances</h1>
      <p>A simple model button that brings up a message in a window:
      <br/>
         <xf:trigger>
            <xf:label>Simple Button</xf:label>
            <xf:message level="modal" ev:event="DOMActivate">Button clicked</xf:message>
         </xf:trigger>
         <br/>
      </p>
      <p>A model button that also displays "hint text" when you hover over the button:
			<br />
         <xf:trigger>
            <xf:label>Button With Hint Text On Hover</xf:label>
            <xf:message level="modal" ev:event="DOMActivate">Button clicked</xf:message>
            <xf:hint>This is the hint text.</xf:hint>
         </xf:trigger>
         <br />
      </p>
      <p>A button that includes an image and hint text:
			<br />
         <xf:trigger appearance="xf:image">
            <img src="XForms-button.jpg" />
            <xf:message level="modal" ev:event="DOMActivate">Image 
clicked</xf:message>
            <xf:hint>This hint text comes up if you hover over a button.</xf:hint>
         </xf:trigger>
         <br />
      </p>
      <p>A button that includes text, and image and text:
			<br />
         <xf:trigger appearance="xf:image">
            <xf:label>Text before the image... <img src="XForms-button.jpg" /> ...text after the image.</xf:label>
            <xf:message level="modal" ref="message" ev:event="DOMActivate" />
            <xf:hint>Hints work with labels and images.</xf:hint>
         </xf:trigger>
         <br />
      </p>
      <p>A trigger that extracts the label, hint and message text from the model:
			<br />
         <xf:trigger>
            <xf:label ref="label" />
            <xf:message level="modal" ref="message" ev:event="DOMActivate" />
            <xf:hint ref="hint" />
         </xf:trigger>
         <br />
      </p>
   </body>
</html>

Discussion[edit]

The XForm specification also uses the xf:help tag. to allow for context sensitive help. This tag would work just like the hint tag but would be activated by the browser or systems help function. You can use a style sheet to also use the help tag.

Next Page: Range | Previous Page: Trigger

Home: XForms



Range

NOTE[edit]

These examples do not appear to work with the FireFox 3 XForms addition. Sliders are hidden with XSLTForms (r406).

Motivation[edit]

You want to use a range control or "slider" to set a numeric value in your form.

Selecting from a continuous range of values[edit]

The range is a control that is part of the XForms specification. It allows the user to select a numeric value from a range of values without using the keyboard. This is ideal for instructors that use interactive learning environments such as a SmartBoard.

The XForms range has four attributes:

  • start - the lower bound of the range
  • end - the upper bound of the range
  • step - the increment of output change
  • incremental - true if the form should send continuous values to the model or false otherwise. The default is false.

These attributes MUST be bound to an element that has a numeric datatype. To do this you must add the following bind statements to your model:

<xf:bind nodeset="/data/my-int" type="xs:integer"/>

<xf:bind nodeset="/data/my-decimal" type="xs:decimal"/>

User Interface[edit]

There are three range controls in this application. The value of the range is on the right side.

XForms Range Screen Image

Link to XForms Application[edit]

Basic Range

Ranges Using Binds

Sample User Interface[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <head>
        <title>XForms Submit Example</title>
        <style type="text/css">
            body {
            font-family: Helvetica, sans-serif;
            }
        </style>
        <xf:model>
            <xf:instance xmlns="">
                <data>
                    <data1>3.14159</data1>
                    <data2>6</data2>
                    <data3>66</data3>
                </data>
            </xf:instance>
            <!-- you MUST bind each data type to the decimal type for the range control to work -->
            <xf:bind nodeset="/data/data1" type="xs:decimal" />
            <xf:bind nodeset="/data/data2" type="xs:decimal" />
            <xf:bind nodeset="/data/data3" type="xs:decimal" />
        </xf:model>
    </head>
    <body>
        <xf:range ref="data1" start="1" end="5" step="1" incremental="true">
            <xf:label>Data1: </xf:label>
        </xf:range>
        <xf:output ref="data1">
            <xf:label> Value= </xf:label>
        </xf:output>
        <br />
        <xf:range ref="data2" start="1" end="10" step="1"  incremental="true">
            <xf:label>Data2: </xf:label>
        </xf:range>
        <xf:output ref="data2">
            <xf:label> Value= </xf:label>
        </xf:output>
        <br />
        <xf:range ref="data3" start="1" end="100" step="5"  incremental="true">
            <xf:label>Data3: </xf:label>
        </xf:range>
        <xf:output ref="data3">
            <xf:label> Value= </xf:label>
        </xf:output>
    </body>
</html>

Testing[edit]

Select one of the three range controls with the mouse. Drag the value to the right or left. You should notice that the values at the right also are updated.

The first control just selects decimals from 1 to 5. The second uses the step to return only integers. The last has a range of 1 to 100 in increments of 5. Note that the value is 66 and you cannot set a value from 62 to 65.

Discussion[edit]

The upper and lower values of the range control can also be set directly in the model. XML Schema provides a minValue and a maxValue that can be used to adjust the range control limits.

W3C Specification[edit]

Here is the specificaion from the W3C web site: W3C range specification


Next Page: Send | Previous Page: Controlling Button Appearance

Home: XForms



Send

Motivation[edit]

You want to send a request to a web server to add additional XML data into your form. This allows different parts of an XForms to defer getting data till it is needed. This makes large forms load faster and avoids unessary network traffic.

Using the send element[edit]

The send element has a single parameter which is submission. This must be the ID of one of the submission elements in your model.

Here is and example:

   <xf:send submission="get-additional-data"/>

If you reference this submission you will need a corresponding submission in your model.

   <xf:model>
      <xf:submission id="get-additional-data" .../>
   </xf:model>

Common Usage[edit]

The most common usage of send is to perform incremental model loading. If you have a large form with many tabs you can wait till the user selects the tab to load the data for this tab.

In the following code fragment, if the user selects tab-5 of the form the submission to load the form data will be sent to the server.

<xf:case id="tab-5">
     <xf:action ev:event="xforms-select" if="not(instance('tab-5-data')/my-data)">
         <xf:send submission="get-tab-5-data"/>
     </xf:action>
     <h2>Tab 5</h2>
</xf:case>

See XForms/Incremental_Model_Loading for an example of how this works.

Next Page: Load | Previous Page: Range

Home: XForms



Load

Motivation[edit]

You want to load a new resource over your current form.

Usage[edit]

In HTML links are simple. You use the HTML anchor tag

<a href="http://example.com">like label</a></nowiki>

However in XForms, it is a bit more complex:

<xf:trigger appearance="minimal">
   <xf:label>Go to Google</xf:label>
   <xf:action ev:event="DOMActivate">
      <xf:load show="replace">
         <xf:resource value="'http://www.google.com'"/>
      </xf:load>
   </xf:action>
</xf:trigger>

The XForms xf:load element has several attributes.

  • ref - a static reference to a single node
  • resource - a static URL such as a relative or absolute URL
  • show - if a new page is created or the current page replaced. Show can have two values: new or replace.
  • target - the target action to be executed

One is the URI of the resource to load and the other is the show attribute. The show attribute can have values of "replace" which will replace the current form with the new resource and "new" which will open a new tab in your web browser or a new window if you are running older browsers such as IE 6.

   <xf:load resource="search.xq" show="new"/>
   <xf:load resource="search.xq" show="replace"/>


xf:load can also be used to run a local javascript function when a form loads:

   <xf:action ev:event="xforms-ready">
      <xf:load resource="javascript:init()"/>
   </xf:action>

Loading Dynamic Strings[edit]

Note that the ref attribute of xf:load can only be a static string. You can not change this as the XForms application changes.

If you need to load dynamic string the way to do this is to use the xf:resource element within the xf:load element. The xf:resource element has a value attribute that is used to hold all the dynamic expressions.

For example the following example concats a URL and the search query from an input field.

   <xf:load show="replace">
     <xf:resource value="concat(url, q)"/>
   </xf:load>

Load with resource attribute value templates[edit]

Some implementations allow you to dynamically create URLs based on data in our mode.

<xf:load ev:event= "DOMActivate"
  resource= "http://www.google.com/{concat(string(instance('instance')/a), '{', '{{',    string(instance('instance')/b), '}', '}}')}/{{something}}/else">
</xf:load>

Releated XForms Examples[edit]

XForms/Search_Using_Load - This example shows how to use a REST search service using the xf:load element XForms/Output_and_Links This example presents the user with a list of links. The user select one from a list and that item is loaded

Next Page: Validation with Bind | Previous Page: Send

Home: XForms



Selecting Text

Motivation[edit]

You want to use a selection list to conditionally populate a text area.

<xf:model>
    <xf:instance id="save-data">
       <data xmlns="">
          <message-type>test-message-1</message-type>
          <current-message/>
       </data>
    </xf:instance>
    
    <xf:instance id="code-table">
       <data xmlns="">
          <messages>
             <message type="test-message-1">Message Type 1</message>
             <message type="test-message-2">Message Type 2</message>
             <message type="test-message-3">Message Type 3</message>
          </messages>
       </data>
    </xf:instance>
    
    <xf:bind nodeset="instance('save-data')/current-message"
        calculate="instance('code-table')/messages/message[@type = instance('save-data')/message-type]"/>
    
    <xf:submission id="post-test" method="post" action="echo-post.xq" 
        instance="save-data" replace="all"/>   
      
</xf:model>

<body>
    <p>Enter a message in the text area below and press the "Submit via HTTP POST" button.</p>
    <div class="block-form">
    {$style}

        <xf:select1 ref="message-type" class="message">
            <xf:label>Message Type:</xf:label>
            <xf:item>
               <xf:label>Test Message 1</xf:label>
               <xf:value>test-message-1</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>Test Message 2</xf:label>
               <xf:value>test-message-2</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>Test Message 3</xf:label>
               <xf:value>test-message-3</xf:value>
            </xf:item>
        </xf:select1>
        
        <xf:textarea ref="current-message">
            <xf:label>Message:</xf:label>
        </xf:textarea>
      
    </div>
     <xf:submit submission="post-test">
         <xf:label>Submit via HTTP POST</xf:label>
       </xf:submit>
</body>



Validation with Bind

Motivation[edit]

You want to validate a single field based on a rule and alert the user if they enter an invalid value.

Method[edit]

We will use an XForms bind expression:

  <xf:bind nodeset="PositiveDecimalAmount" 
      type="xs:decimal" 
      constraint=". > 0"/>

This last line says that if the current element is greater than zero then the rule passes and the field is valid.

Screen Image[edit]

Example of error on bind

Sample Code[edit]

   <html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    >
    <head>
        <title>Validation With Bind</title>
        <style type="text/css">
        <![CDATA[
            body {
            font-family: Helvetica, sans-serif;
            }
        ]]>
        </style>
        <xf:model>
            <xf:instance xmlns="">
               <data>
                    <PositiveDecimalAmount>1.0</PositiveDecimalAmount>
                    <NegativeDecimalAmount>-1.0</NegativeDecimalAmount>
                </data>
            </xf:instance>
            
            <!-- note that the gt operator does not work and that the greater than character must be escaped.  -->
            <xf:bind nodeset="PositiveDecimalAmount" type="xs:decimal" required="false()" constraint=". &gt; 0"/>
            
            <!-- note that the lt operator does not work and that the less than character must be escaped.  -->
            <xf:bind nodeset="NegativeDecimalAmount" type="xs:decimal" required="false()" constraint=". &lt; 0"/>


        </xf:model>
    </head>
    <body>
        <h1>Validation With Bind</h1>
        <p>To pass this test the form must warn the user if they enter </p>
        
            <xf:input class="PositiveDecimalAmount" ref="PositiveDecimalAmount" incremental="true">
                <xf:label>Positive Decimal Amount:</xf:label>
                <xf:alert>Amount must be a positive decimal number.</xf:alert>
            </xf:input>
            <br/>
            <xf:input class="NegativeDecimalAmount" ref="NegativeDecimalAmount" incremental="true">
                <xf:label>Negative Decimal Amount:</xf:label>
                <xf:alert>Amount must be a negative decimal number.</xf:alert>
            </xf:input>
            <br/>
    </body>
</html>

Next Page: Case Validation | Previous Page: Load

Home: XForms



Case Validation

Motivation[edit]

You want to check to see if a field is upper or lower case.

Note: This does not seem to work in FireFox or XSLTForms.

Method[edit]

We will use a bind constraint.


  <xf:bind nodeset="UpperCaseText" type="xs:string"  
           constraint="
                 . eq translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') 
                     "/>

Sample Source Code[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    >
    <head>
        <title>Case Test</title>
        <style type="text/css">
        <![CDATA[
            body {
            font-family: Helvetica, sans-serif;
            }
        ]]>
        </style>
        <xf:model>
            <xf:instance xmlns="">
               <data>
                    <LowerCaseText>abc</LowerCaseText>
                    <UpperCaseText>ABC</UpperCaseText>
                </data>
            </xf:instance>
            
            
            <xf:bind nodeset="UpperCaseText" type="xs:string"  
            constraint="
                  . eq translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') "/>
           
            <!-- compare the string to the lower-case version.  If they are the same we pass -->
            <xf:bind nodeset="LowerCaseText" type="xs:string" 
            constraint="
                    . eq translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') "/>
   
        </xf:model>
    </head>
    <body>
        <h1>Case Test</h1>
        <p>To pass this test the form must warn the user if they enter an invalid string. 
        The XForms alert message
        must also be visible.</p>
        
            <xf:input ref="LowerCaseText" incremental="true">
                <xf:label>Lower Case String:</xf:label>
                <xf:alert>The string must contain lowercase only.</xf:alert>
            </xf:input>
            <br/>
            
            <xf:input  ref="UpperCaseText" incremental="true">
                <xf:label>Upper Case String:</xf:label>
                <xf:alert>The string must contain uppercase only.</xf:alert>
            </xf:input>
            <br/>
    </body>
</html>


Next Page: Submit | Previous Page: Validation with Bind

Home: XForms



Limiting Length

Motivation[edit]

You want to warn a user that an input control exceeds a specified length.

Method[edit]

We will use the XForms "action" element and conditionally display a message if the string-length is larger than 50 characters. The following action should be placed within the control.

<xf:action ev:event="xforms-value-changed" if="string-length(.) &gt; 50">
   <xf:message level="modal">maximum length is 50 characters</xf:message>
</xf:action>

Example with Textarea[edit]

<xf:textarea ref="short-message" incremental="true">
   <xf:label>Message:</xf:label>
      <xf:action ev:event="xforms-value-changed" if="string-length(.) &gt; 140">
         <xf:message level="modal">Maximum message length is 140 characters.</xf:message>
      </xf:action>
</xf:textarea>
<xf:output ref="short-message"/>



Server-Side Field Validation

Motivation[edit]

Steps[edit]

Step 1: Add instances for outgoing and incoming data[edit]

<!-- store the outgoing data for the invalid e-mail check -->
<xf:instance id="email-out">
   <data xmlns="">
      <email></email>
   </data>
</xf:instance>


<!-- place to store the results of an invalid e-mail check -->
<xf:instance id="email-check-results">
   <data xmlns=""/>
</xf:instance>

Step 2: Add a submission element to the model[edit]

The submission element connects the "field changed" event to a service on the server.

<xf:submission id="email-check" method="get" action="email-check.xq" 
           ref="instance('email-check')" 
           replace="instance" instance="email-check-results" />

Step 3: Add an action to your input[edit]

<xf:input ref="email" >
    <xf:label>Email: </xf:label>
    <xf:hint>This field must contain a valid email format.</xf:hint>
    <xf:action ev:event="xforms-value-changed">
           <!-- copy from your "save-data" into the outgoing instance -->
           <xf:setvalue ref="instance('email-out')/email" value="instance('save-data')/email"/>
           <xf:send submission="email-check"/>
    </xf:action>
</xf:input>

Step 4: Add a group that displays errors if the results are invalid[edit]

<xf:group ref="instance('email-check-results')/message[@class='error']">
     <div class="field-warn"><xf:output value="instance('email-check-results')/message"/></div>
</xf:group>

Step 5: Create a server-side REST GET service that returns true/false[edit]

If there are no errors just return <ok/>

If there are errors return
<message type="error">Invalid e-mail format</message>



Submit

The Submit Element[edit]

One of the reasons that we have been careful to store all of our data in the model is that once this is done it makes it easy for a web client to simply serialize this model into XML and send it to a file, a web service, or possibly to a database.

This is all done by using a simple submit command. submit is really just a trigger with an attribute of submission that points to a submission element in the model. This is usually a button with the word "Submit" or "Save" on it that appears at the end of the form.

On many HTML forms you fill out the form and press a button at the bottom of the form called "Save" or "Submit". You pressed the button and hoped your data would get saved. This is the same concept. But in this case the submit command can be triggered in many ways other that just a button being pressed and there are explicit ways of getting feedback from the receiver that the submission process succeeded.

The submit event behaves exactly like a trigger but with one key exception, the xforms-submit event is also dispatched.

A model can have more than one submission identified by id

  • <xforms:submission id="s001" method="post" action="action.php"/>
  • <xforms:submission id="s002" method="post" action="action2.php" replace="instance"/>
  • <xforms:submission id="s003" method="put" action="file:///tmp/final.xml"/>

The first submission sends the data to the specified action, while the second one will expect to get a return xml to update the current document/instance. The third one will save the file locally to the given location /tmp/final.xml

Screen Image[edit]

The interface is very simple. It is just a simple "Save" button created by a trigger called submit.

XForms save button

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>XForms Submit Example</title>
      <xf:model>
         <xf:instance xmlns="">
            <MyData>
               <Data1>One</Data1>
               <Data2>Two</Data2>
               <Data3>Three</Data3>
            </MyData>
         </xf:instance>
         <xf:submission id="save" method="put" action="myData.xml" ref="/MyData"/>
      </xf:model>
   </head>
   <body>
       <xf:submit submission="save">
         <xf:label>Save</xf:label>
      </xf:submit>
   </body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/20021/XMLSchema-instance">
    
    <head>
        <title>Submission with get and put</title>
        <xf:model>
            <xf:instance id="data_instance" src="data.xml" xmlns=""></xf:instance>
            <xf:submission id="read-from-file" method="get" action="data.xml" replace="instance"
                instance="data-instance"></xf:submission>
            <xf:submission id="save-to-file" method="put" action="data.xml" replace="instance"
                instance="data_instance"></xf:submission>
        </xf:model>
    </head>
    <body>
        <p>Demonstration of using XForms to get and put data to local file using the submission
            element.</p>
        <xf:input ref="Element1">
            <xf:label>Element1:</xf:label>
        </xf:input>
        <br />
        <xf:input ref="Element2">
            <xf:label>Element2:</xf:label>
        </xf:input>
        <br />
        <xf:input ref="Element3">
            <xf:label>Element3:</xf:label>
            <br />
        </xf:input>
        <xf:submit submission="read-from-file">
            <xf:label>Reload</xf:label>
        </xf:submit>
        <xf:submit submission="save-to-file">
            <xf:label>Save</xf:label>
        </xf:submit>
    </body>
</html>

Analysis[edit]

The save button is really just a trigger with the name of "submit" and an attribute called submission.

   <xf:submit submission="save">

The attribute submission="save" points to the ID of the submission element inside the model.

   <xf:submission id="save" method="put" action="myData.xml" ref="/MyData"/>

Note that because we used a "relative file name" (relative to the directory that the form was in) it will save the data in the same directory location that the form was located.

Discussion[edit]

You can also use absolute path names but you must be careful about how you describe a letter drive since there are no standards for this.

The following format worked for a Microsoft Windows system using the FireFox browser:

   <xf:submission id="save" method="put" action="file:/C:/tmp/myData.xml" ref="/MyData"/>

Web Server Configuration[edit]

Note: This section was written by a person that does not know much about web server administration. Read at your own risk and make sure a security professional reviews any changes to your public web servers.

Most of the examples in this tutorial are about learning XForms, not web server administration. That being said there are a few things we thought might be useful.

By default web servers are usually not configured to write files to your web server. Especially by un-authorized users. If this were the case hackers might use your web server to store their adult content.

To get XForms to save instance using "put", you should only allow writing to authorized users. To do this you will need to be able to administer your web server correctly.

Apache 2.2 Intranet Configuration with DAV[edit]

If you have a computer that is only accessible by internal users (usually called an Intranet) you can access, you can add the following to your Apache configuration file (usually called httpd.config and located in /usr/local/etc or similar location):

First, the following modules may have to be loaded:

mod_dav, mod_dav_fs, mod_dav_svn, mod_authz_svn.

This can be done by adding the following lines to your httpd.conf file:

LoadModule dav_module libexec/apache22/mod_dav.so
LoadModule dav_fs_module libexec/apache22/mod_dav_fs.so
<Directory "usr/local/www/apache22/data/forms/read-write-test">
   DAV on
   AllowOverride None
   Order allow,deny
   Allow from all
</Directory>

By turning on DAV you will enable all of the WebDAV operations including "PUT".

IIS Configuration[edit]

To be done...

References[edit]


Next Page: Encoding Parameters | Previous Page: Case Validation

Home: XForms



Encoding Parameters

Motivation[edit]

When you submit data to a web service you want to change the way that parameters are encoded.

Method[edit]

Changing the Separator Character[edit]

By default the separator character is a semicolon. You can change it to be an ampersand by adding the following attribute to the submission element:

  separator="&amp;"

Note that the ampersand must be escaped.

(09 MAR 2009 the default was changed to ampersand in the official xsd-file)

Changing the URL encoding Parameter[edit]

You can also change the way that special characters are encoded by using the encoding attribute.

The options are any of the character encoding systems such as:

encoding="ISO-8859-1"

encoding="UTF-16"

Discussion[edit]

Next Page: Changing Namespaces in Submission | Previous Page: Submit

Home: XForms



Changing Namespaces in Submission

Motivation[edit]

You want to control the way that namespace prefixes are handled in your submission.

Method[edit]

We will use the includenamespaceprefixes attribute of a submission.

The XForms 1.1 specification allows the user to change the way that namespace prefixes are handled in a submitted element.

Here is an example of the use of the includenamespaceprefixes attribute to the submission element.

<xf:submission action="http://example.com/submit" 
   method="post" id="submit" 
   includenamespaceprefixes=""/>
<xf:submission action="http://example.com/submit" 
   method="post" includenamespaceprefixes="#default"/>

Sample Form[edit]

<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"
    xmlns:task="http://www.example.com/task"
    task:dummy="dummy">
    <head>
        <title>Test of XForms Submission Namespace Inclusion</title>
        <style type="text/css">
            <![CDATA[
            @namespace xf url("http://www.w3.org/2002/xforms");
            body {font-family:Helvetica, sans-serif;}
             .block-form xf|input { display: block; margin: 1ex; }
             .block-form xf|label {display: inline-block; width: 15ex; float: left; text-align: right; margin-right: 1ex; font-weight: bold;}
            ]]>
        </style>
        <xf:model>
            <xf:instance src="input-default-ns.xml" id='save-data'/>
            
            <xf:submission id="submit-std"
                action="http://localhost:8080/exist/rest/db/test/xforms/submission-tests/save-new.xq" 
                method="post"/>
                
            <xf:submission id="submit-null"
                action="http://localhost:8080/exist/rest/db/test/xforms/submission-tests/save-new.xq" 
                method="post"  
                includenamespaceprefixes=""/>
            
            <xf:submission id="submit-default"
                action="http://localhost:8080/exist/rest/db/test/xforms/submission-tests/save-new.xq" 
                method="post"  
                includenamespaceprefixes="#default"/>
                
        </xf:model>
    </head>
    <body>
        <h1>Submit Test</h1>
        <div class="block-form">
           <xf:input ref="instance('save-data')/task:id">
               <xf:label>ID: </xf:label>
           </xf:input>
   
               <xf:input ref="task:task-name">
               <xf:label>Name: </xf:label>
           </xf:input>
   
               <xf:input ref="task:task-description">
               <xf:label>Description: </xf:label>
           </xf:input>
        </div>
        
        <xf:submit submission="submit-std">
            <xf:label>Without Attribute</xf:label>
        </xf:submit>
        <xf:submit submission="submit-null">
            <xf:label>With Attribute Null</xf:label>
        </xf:submit>
        <xf:submit submission="submit-default">
            <xf:label>With Default Namespace</xf:label>
        </xf:submit>
    </body>
</html>

Sample Instance Files[edit]

With Default Namespace[edit]

<task xmlns="http://www.example.com/task">
    <task:id>123</task:id>
    <task-name>Task Name</task-name>
    <task-description>Task Description</task-description>
</task>

With Namespace Prefixes[edit]

<task:task xmlns:task="http://www.example.com/task">
    <task:task:id>123</task:id>
    <task:task-name>Task Name</task:task-name>
    <task:task-description>Task Description</task:task-description>
</task:task>

Link to Working Example[edit]

Example Introduction to XForms 1.1 Submission Differences

Next Page: Events Overview | Previous Page: Encoding Parameters

Home: XForms



Displaying Save Results

Motivation[edit]

After a save, you want to display a line at the end of your form to confirm that the results have been saved to the server. You also want to notify the user of any errors after a save.

Method[edit]

We will use the submission element to save the data and return the save results. We will use the <xf:group> to show either a success (in green) or a failure (in red).

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fr="http://orbeon.org/oxf/xml/form-runner" xmlns:xxforms="http://orbeon.org/oxf/xml/xforms" xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
        <title>Save Test</title>
        <xf:model>
            <xf:instance xmlns="" id="save-data">
                <formdata form-id="unit-tests-save-test">
                    <first-name>Dan</first-name>
                    <last-name>McCreary</last-name>
                </formdata>
            </xf:instance>
            <xf:instance xmlns="" id="save-results">
                <save-results>
                    <message>No Save Results Yet</message>
                </save-results>
            </xf:instance>
            <xf:submission id="save-submission" ref="instance('save-data')" 
                method="post" resource="http://localhost:8088/exist/rest/db/apps/grants/scripts/save.xq" 
                replace="instance"
                instance="save-results">
                <xf:action ev:event="xforms-submit-done">
                    <xf:message>Save Done</xf:message>
                </xf:action>
                <xf:action ev:event="xforms-submit-error">
                    <xf:message>Save Failed</xf:message>
                </xf:action>
            </xf:submission>
            <xf:submission id="save-submission-see-save-results" ref="instance('save-data')" 
                method="post" resource="http://localhost:8088/exist/rest/db/apps/grants/scripts/save.xq" replace="instance" 
                instance="save-results">
                <xf:action ev:event="xforms-submit-done">
                    <xf:message>Save Done</xf:message>
                </xf:action>
                <xf:action ev:event="xforms-submit-error">
                    <xf:message>Save Failed</xf:message>
                </xf:action>
            </xf:submission>
        </xf:model>
        <style type="text/css">
            .success {color: green; background-color: lightgreen;}
            .failure {color: red; background-color: pink;}
        </style>
    </head>
    <body>
        <xf:input ref="first-name">
            <xf:label>First name:</xf:label>
        </xf:input>
        <br/>
        <xf:input ref="last-name">
            <xf:label>Last name:</xf:label>
        </xf:input>
        <a href="http://localhost:8088/exist/rest/db/apps/xforms/scripts/save.xq">Save URL</a>
        <div class="save-controls">
            <xf:submit submission="save-submission" appearance="xxforms:primary" class="button-margin-top">
                <xf:label>Save and Validate</xf:label>
            </xf:submit>
            <xf:submit submission="save-submission-see-save-results" class="button-margin-top">
                <xf:label>Save See Save Results</xf:label>
            </xf:submit>
        </div>
        <xf:group ref="instance('save-results')/.[@code='200']">
            <div class="success">
               <xf:output ref="instance('save-results')//message"/>
            </div>
        </xf:group>
        <xf:group ref="instance('save-results')/.[@code='400']">
            <div class="failure">
                <xf:output ref="instance('save-results')//message"/>
            </div>
        </xf:group>
    </body>
</html>

Sample XQuery[edit]

xquery version "1.0";
import module namespace config= "http://danmccreary.com/config" at "../modules/config.xqm";

declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare namespace xf="http://www.w3.org/2002/xforms";
declare namespace dc="http://gov/grantsolutions/dc";

let $log := util:log-system-out('running save.xq')
(: get-data() returns the document node.  We want the root node :)
let $formdata := request:get-data()/*

(: check to make sure we have valid post data :)
return
  if (not($formdata))
     then <save-results code="400">No Post Data</save-results>
     else 

let $save-data-collection := concat($config:app-home-collection, '/save-data')

let $form-id :=
   if (exists($formdata/@code))
      then $formdata/@code/string()
      else
        if (exists($formdata/@form-id))
            then $formdata/@form-id/string()
            else 'unknown-form-id'
      
let $file-name := concat($form-id, '.xml')
let $path-name := concat($save-data-collection, '/', $file-name)

let $overwrite :=
  if (doc-available($path-name))
    then true()
    else false()
    
let $store := xmldb:store($save-data-collection, $file-name, $formdata)

return
<save-results code="200">
    {if ($overwrite)
        then <message>Document updated at {$path-name}</message>
        else <message>New document saved to {$path-name}</message>
    }
</save-results>



Events Overview

Motivation[edit]

You want to be able to perform various tasks at various part of the form execution.

Method[edit]

XForms is integrated with the W3C XML Event standard. This standard creates standard names for almost all of the common events used in the lifecycle of a form. The W3C has attempted to standardize these events and their event labels so that they can be used consistently across browsers from all vendors.

XML Event Types[edit]

The following is a listing of the XForms events. Some events are tied to individual forms controls such as input, select and textarea and some are tied to the model within the form.

XForms events
Event Cancel Bubbles Target
Initialization Events
xforms-model-construct N Y <model>
xforms-model-construct-done N Y <model>
xforms-ready N Y <model>
xforms-model-destruct N N <model>
Processing Events
xforms-rebuild Y Y <model>
xforms-recalculate Y Y <model>
xforms-revalidate Y Y <model>
xforms-refresh Y Y <model>
Interaction Events
xforms-previous Y N <control>
xforms-next Y N <control>
xforms-focus Y N <control>
xforms-help Y Y <control>
xforms-hint Y Y <control>
xforms-reset Y Y <model>
xforms-submit Y Y <submission>
DOMActivate Y Y <control>
Notification Events
DOMFocusIn N Y <control>
DOMFocusOut N Y <control>
xforms-value-changed N Y <control>
xforms-select N Y <item>, <case> or <itemset>
xforms-deselect N Y <item>, <case> or <itemset>
xforms-scroll-first N Y <repeat>
xforms-scroll-last N Y <repeat>
xforms-insert N Y <instance>
xforms-delete N Y <instance>
xforms-valid N Y <control>
xforms-invalid N Y <control>
xforms-in-range N Y <control>
xforms-out-of-range N Y <control>
xforms-readonly N Y <control>
xforms-readwrite N Y <control>
xforms-required N Y <control>
xforms-optional N Y <control>
xforms-enabled N Y <control>
xforms-disabled N Y <control>
xforms-submit-done N Y <submission>
xforms-submit-error N Y <submission>
Error Notifications
xforms-binding-exception N Y <bind>
xforms-link-exception N Y <model>
xforms-link-error N Y <model>
xforms-compute-exception N Y <model>

Displaying Events in a Log File[edit]

One of the best ways to learn about how events get fired is to write them to a log instance and display the log at the bottom of the form. You can do this logging while you are building and debugging your form.

Add the following instance to your model:

<xf:instance xmlns="" id="log">
    <events>
       <event>log initialized</event>
    </events>
</xf:instance>

Whenever you want to see an event, just add an action that appends an event to the end of the log:

<xf:action ev:event="xforms-deselect">
    <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
    <xf:setvalue ref="instance('log')/event[last()]" value="'Tab One deselected'" />
</xf:action>

Note that the message must be inside a pair of single quotes inside of double quotes.

At the end of the form you can display the data from the log instance by enclosing the output within a repeat.

<div id="event-log">
   <xf:repeat nodeset="instance('log')/event" class="log">
      <xf:output ref="." />
   </xf:repeat>
</div>

You can also style the event log with the following

#event-log {
   color: DarkGray;
   background-color: Lavender;
}



Setting Initial Cursor

Motivation[edit]

When a form loads you want to set the initial cursor position so the user's first keystrokes are entered into the first field. This prevents the user from having to select the the first field on a form with the mouse. Although some people consider this "polish" it is the hallmark of a conscientious developer.

Method[edit]

To perform this task you must do two things. First you need to give the control you want to receive the first keystroke event an id attribute. For example:

<xf:input id="first-field">
   <xf:label>Search</xf:label>
</xf:input>

The next step is to use the xforms-ready event to set the focus to this field using the setfocus element.

These initial actions are usually placed at the end of the model in the html header but before the body.

<xf:model>
   ...
   <xf:action ev:event="xforms-ready">
      <xf:setfocus control="first-field" />
   </xf:action>
   ...
</xf:model>

Link to XForms Application[edit]

Load XForms Application

Source Code[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   xmlns:ev="http://www.w3.org/2001/xml-events" >
   <head>
      <title>Initial Cursor Positioning</title>
      <xf:model>
          <xf:instance xmlns="">
              <data>
                  <element1/>
              </data>
          </xf:instance>

      <xf:action ev:event="xforms-ready">
         <xf:setfocus control="first-field" />
      </xf:action>
      </xf:model>
   </head>
   <body>
      <h3>Initial Cursor Positioning</h3>
      <xf:input ref="element1" id="first-field">
         <xf:label>Element One:</xf:label>
      </xf:input>
   </body>
</html>

Next Page: Selection and Deselection Events | Previous Page: Events Overview

Home: XForms



Selection and Deselection Events

Motivation[edit]

You want to perform actions based on a tab being selected or deselected. For example you may want to defer loading large parts of a complex model until a tab is selected.

Method[edit]

This example uses event logging to show how the selection and deselection events are used.

Screen Image[edit]

Logging tab selection and deselection events

Sample Code[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Logging Tab Selection and Deselection Events</title>
      <style type="text/css">
            @namespace xf url("http://www.w3.org/2002/xforms");
            body {font-family: Helvetica, sans-serif;}
        /* style each individual tab */
        #tab-bar xf|trigger {
        color: black;
        border: 3px outset gray; 
        border-bottom: none;
        font-weight: bold;
        margin-right: 5px;
        padding: 0.2em;
        /* round the top corners - works only with FireFox */
        -moz-border-radius: .5em .5em 0em 0em;
        }
        
        .log {
        background: lavender;
        border: solid blue 1px;
        }
        </style>
      <xf:model>
         <xf:instance xmlns="" id="image">
            <data />
         </xf:instance>
         <xf:instance xmlns="" id="log">
            <events>
               <event>log initialized</event>
            </events>
         </xf:instance>
         <xf:action ev:event="xforms-ready">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'xforms-ready event'" />
         </xf:action>
      </xf:model>
   </head>
   <body>
      <h1>Logging Tab Selection and Deselection Events</h1>
      <p>The selection and deselection event will generate a message in the event log each time a tab is selected.</p>
      <div id="tab-bar">
         <xf:trigger appearance="minimal">
            <xf:label>Tab One</xf:label>
            <xf:toggle case="case-1" ev:event="DOMActivate" />
         </xf:trigger>
         <xf:trigger appearance="minimal">
            <xf:label>Tab Two</xf:label>
            <xf:toggle case="case-2" ev:event="DOMActivate" />
         </xf:trigger>
         <xf:trigger appearance="minimal">
            <xf:label>Tab Three</xf:label>
            <xf:toggle case="case-3" ev:event="DOMActivate" />
         </xf:trigger>
      </div>
      <xf:switch>
         <xf:case id="case-1">
            <xf:action ev:event="xforms-select">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'Tab One selected'" />
            </xf:action>
            <xf:action ev:event="xforms-deselect">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'Tab One deselected'" />
            </xf:action>
            <h1>Tab One</h1>
         </xf:case>
         <xf:case id="case-2">
            <xf:action ev:event="xforms-select">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'Tab Two selected'" />
            </xf:action>
            <xf:action ev:event="xforms-deselect">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'Tab Two deselected'" />
            </xf:action>
            <h1>Tab Two</h1>
         </xf:case>
         <xf:case id="case-3">
            <xf:action ev:event="xforms-select">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'Tab Three selected'" />
            </xf:action>
            <xf:action ev:event="xforms-deselect">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after" />
               <xf:setvalue ref="instance('log')/event[last()]" value="'Tab Three deselected'" />
            </xf:action>
            <h1>Tab Three</h1>
         </xf:case>
      </xf:switch>
      <xf:repeat nodeset="instance('log')/event" class="log">
         <xf:output ref="." />
      </xf:repeat>
   </body>
</html>

Discussion[edit]

Note that you must wrap the xf:setvalue values in a double quote and a single quote to append strings to the events.

Next Page: Conditional Actions | Previous Page: Setting Initial Cursor

Home: XForms



Conditional Actions

Motivation[edit]

You want to conditionally perform an action based on an XPath Expression.

Method[edit]

We will use the if attribute of an action that is part of the XForms 1.1 specification. We will set up an event that will be triggered every time an instance becomes empty. We will create an action and set the observer attribute to watch for changes in the people instance.

Here is the code for the action itself:


<xf:action
   ev:event="xforms-delete"
   ev:observer="people"
   if="not(person)">
        <xf:insert origin="instance('person-template')" context="."/>
</xf:action>

This says to watch the people instance and if there is not a person in the people instance then insert one using the person-template instance.

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema-datatypes"
    xmlns:ev="http://www.w3.org/2001/xml-events">
  <head>
    <title>Test of populating a repeat if it becomes empty</title>

    <xf:model id="m">
      <xf:instance id="people">
        <people xmlns="">
          <person>
            <name>John</name>
            <email>j...@example.org</email>
          </person>
          <person>
            <name>Bethany</name>
            <email>beth...@example.org</email>
          </person>
        </people>
      </xf:instance>

      <xf:instance id="person-template">
        <person xmlns=""><name/> <email/></person>
      </xf:instance>
    </xf:model>
  </head>

  <body>        
    <h1>Test of populating a repeat if it becomes empty</h1>

    <xf:group ref="instance('people')">
      <xf:repeat nodeset="person">
        <xf:input ref="name"><xf:label>Name: </xf:label></xf:input><br/>
        <xf:input ref="email"><xf:label>Email address: </xf:label></xf:input>

        <xf:trigger>
          <xf:label>Delete</xf:label>

          <xf:delete ev:event="DOMActivate" nodeset="."/>
        </xf:trigger>
      </xf:repeat>

      <xf:action ev:event="xforms-delete" ev:observer="people"
                 if="not(person)">
        <xf:insert origin="instance('person-template')" context="."/>
      </xf:action>
    </xf:group>
  </body>
</html>

Acknowledgments[edit]

This example was posted on the Mozilla XForms newsgroup by John L. Clark in December 10th of 2008.




Binds to many instances

Motivation[edit]

You often want to be able to bind to different instances in different models. This sample program shows you how to do this. Creating separated models is critical to allow clean submissions. You should always structure so that your submission data is in a single model. But this creates problems when referencing data elements without specifying what model the instance is part of.

Note in the example below the group element encloses the output for each model.

Screen Image[edit]

Binding to instances in multiple models

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:foobar="http://www.example.com">
   <head>
      <title>Binds to Multiple Instances in Multiple Models</title>
      <style type="text/css">
         @namespace xf url("http://www.w3.org/2002/xforms");
         body {font-family: Helvetica,sans-serif}
         xf|label {font-weight: bold}
      </style>
      
      <xf:model id="model-1">
      
         <xf:instance id="instance-1-1" xmlns="">
            <Data>
               <Message>Hello World Model 1 Instance 1!</Message>
            </Data>
         </xf:instance>
         <xf:bind id="bind-1-1" nodeset="instance('instance-1-1')/Message" />
         
         <xf:instance id="instance-1-2" xmlns="">
            <Data>
               <Message>Hello World Model 1 Instance 2!</Message>
            </Data>
         </xf:instance>
         <xf:bind id="bind-1-2" nodeset="instance('instance-1-2')/Message" />
         
      </xf:model>
      
      <xf:model id="model-2">
      
         <xf:instance id="instance-2-1" xmlns="">
            <Data>
               <Message>Hello World Model 2 Instance 1!</Message>
            </Data>
         </xf:instance>
         <xf:bind id="bind-2-1" nodeset="instance('instance-2-1')/Message" />
         
         <xf:instance id="instance-2-2" xmlns="">
            <Data>
               <Message>Hello World Model 2 Instance 2!</Message>
            </Data>
         </xf:instance>
         <xf:bind id="bind-2-2" nodeset="instance('instance-2-2')/Message" />
         
      </xf:model>
      
   </head>
   
   <body>
   <h1>Model 1</h1>
      <xf:group model="model-1">
         <xf:output ref="instance('instance-1-1')/Message">
            <xf:label>ref="instance('instance-1-1')/Message":</xf:label>
         </xf:output>
         <br/>
         <xf:output bind="bind-1-1">
            <xf:label>bind="bind-1-1":</xf:label>
         </xf:output>
         <br/>
         <xf:output ref="instance('instance-1-2')/Message">
            <xf:label>ref="instance('instance-1-2')/Message":</xf:label>
         </xf:output>
         <br/>
         <xf:output bind="bind-1-2">
            <xf:label>bind="bind-1-2":</xf:label>
         </xf:output>
      </xf:group>
      <h1>Model 2</h1>
      <xf:group model="model-2">
         <xf:output ref="instance('instance-2-1')/Message">
            <xf:label>ref="instance('instance-2-1')/Message":</xf:label>
         </xf:output>
         <br/>
         <xf:output bind="bind-2-1">
            <xf:label>bind="bind-2-1":</xf:label>
         </xf:output>
         <br/>
         <xf:output ref="instance('instance-2-2')/Message">
            <xf:label>ref="instance('instance-2-2')/Message":</xf:label>
         </xf:output>
         <br/>
         <xf:output bind="bind-2-2">
            <xf:label>bind="bind-2-2":</xf:label>
         </xf:output>
      </xf:group>
   </body>
</html>

Discussion[edit]

Note that you can not bind across models. This implies that complex calculations that need to access instance data in multiple models need to copy them into a single model before calculations are done.

Next Page: Bind to ranges | Previous Page: Conditional Actions

Home: XForms



Bind to ranges

Motivation[edit]

Your output can be created from calculations from many inputs. The rules behind these calculations (sometimes called business rules) should be stored in the model, not the view.

Screen Image[edit]

This program has two inputs and one output. The output is calculated by multiplying the two inputs together. As you move the range controls the output should be updated.

Xforms-bind-range-multiplier.jpg

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml"   
  xmlns:xf="http://www.w3.org/2002/xforms" 
  xmlns:ev="http://www.w3.org/2001/xml-events" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <head>
      <title>Example of binding to inputs and output ids</title>
      <xf:model id="model">
         <xf:instance id="input">
            <Data xmlns="">
               <InputValueOne>3</InputValueOne>
               <InputValueTwo>3</InputValueTwo>
            </Data>
         </xf:instance>
         <!-- make the inputs data types be integers -->
         <xf:bind id="input-one-bind" nodeset="/Data/InputValueOne" type="xs:integer"/>
         <xf:bind id="input-two-bind" nodeset="/Data/InputValueTwo" type="xs:integer"/>
         <!-- second instance bound to outputs -->
         <xf:instance id="output">
            <DataOut xmlns="">
               <OutputValue>9</OutputValue>
            </DataOut>
         </xf:instance>
         <!-- Make the output be an integer that is the the product of the inputs -->
         <xf:bind id="output-bind" nodeset="instance('output')/OutputValue" calculate="instance('input')/InputValueOne * instance('input')/InputValueTwo" type="xs:integer"/>
      </xf:model>
   </head>
   <body>
      <p>
         <xf:range bind="input-one-bind" start="1" end="5" step="1" incremental="true">
            <xf:label>Input: </xf:label>
         </xf:range>
         <br/>
         <xf:range bind="input-two-bind" start="1" end="5" step="1" incremental="true">
            <xf:label>Input: </xf:label>
         </xf:range>
     <br/>
        <xf:output bind="input-one-bind"/> * <xf:output bind="input-two-bind"/> =
         <xf:output bind="output-bind"/>
      </p>
   </body>
</html>

Discussion[edit]

Note that the output is just inputs and outputs. The calculation that multiplies the two inputs together is done in the output bind statement.

<xf:bind id="output-bind" 
   nodeset="instance('output')/OutputValue"
   calculate="instance('input')/InputValueOne *
              instance('input')/InputValueTwo"
   type="xs:integer"/>

References[edit]

Next Page: Repeat | Previous Page: Binds to many instances

Home: XForms



Repeat

Here is a simple example of how to get a list of repeating data elements out to your screen. This is done using the repeat tag and the nodeset attribute. You use the nodeset to specify where you want to begin your listing in the model. In this case we are just using a model embedded into the page.

Output[edit]

Here is the output for this program under the FireFox browser:

XForms-phone-list.jpg

Note that all of the names are displayed, not just the first name. Note how we are mixing both HTML tags and XForms tags together in the body.

Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Phone List</title>
      <xf:model>
         <xf:instance xmlns="" id="phonebook">
            <PhoneList>
               <Person>
                  <Name>Peggy</Name>
                  <Phone>123</Phone>
               </Person>
               <Person>
                  <Name>Dan</Name>
                  <Phone>456</Phone>
               </Person>
               <Person>
                  <Name>John</Name>
                  <Phone>789</Phone>
               </Person>
               <Person>
                  <Name>Sue</Name>
                  <Phone>234</Phone>
               </Person>
            </PhoneList>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <fieldset>
         <legend>Company Phone List</legend>
         <p><b>Name, Phone</b>
         <xf:repeat nodeset="Person">
            <xf:output ref="Name"/>,
            <xf:output ref="Phone"/>
         </xf:repeat>
         </p>
      </fieldset>
   </body>
</html>

Discussion[edit]

The key line here is the repeat statement:

   <xf:repeat nodeset="Person">

The repeat element has an attribute named nodeset. This tells you where in your model to get the data. In this case we will be iterating over all Person records and outputting the Name and Phone for each Person.

As an alternative you can also use an instance reference:

   <xf:repeat nodeset="instance('phonebook')/Person">

You can also use an absolute path reference:

   <xf:repeat nodeset="/PhoneList/Person">


Note that each <repeat> starts a new line for each person record. This can be turned into a clean tabular layout using a simple style sheet. You can do this by having the second output be associated with a class called "column2" and then adding a column2 formatting rule to the style sheet.

Next Page: Conditional Styling | Previous Page: Bind to ranges

Home: XForms



Conditional Styling

Motivation[edit]

You have a list of items that you want to display inside of a repeat loop. You want some items to have different styling based on the content of items.

Method[edit]

We will use the XForms group element to conditionally display an item inside of the repeat statement.

Sample XML Fragement[edit]

Assume your form has the following data in an instance:

<my-nodes>
   <my-node>
      <element1>true</element1>
      <element2>Element2 Value</element2>
   </my-node>
   <my-node>
      <element1>false</element1>
      <element2>Element2 Value</element2>
   </my-node>
   <my-node>
      <element1>true</element1>
      <element2>Element2 Value</element2>
   </my-node>
</my-nodes>

Conditional Display of Items[edit]

The following text will only output element2 when element1 has a value of true.

<xf:repeat nodeset="//my-node">
   <xf:group ref=".[element1='true']">
      <xf:output ref="element2"/>
   </xf:group>
</xf:repeat>

The syntax .[a='b'] says that from the current node if the element a equals the value b then output the elements within the group.

Conditional Formatting of Items[edit]

This same strategy can be used to enclose output in different div or span elements.

<xf:repeat nodeset="my-node">
   <xf:group ref=".[element1='true']">
      <xf:output ref="element2" class="strong"/>
   </xf:group>
   <xf:group ref=".[element1='false']">
      <xf:output ref="element2"/>
   </xf:group>
</xf:repeat>

In the above example all nodes with element1='true' will have a class="strong" in the output and any element with element1='false' will not have the attribute in the output.

Sample XForms Appliction[edit]

Load XForms Application

Source Code[edit]

In this example we need to display a list of synonyms for a specific term. The Synonyms are all listed and a preferred term is displayed with a bold font.

<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>
       <title>Conditional Display</title>
       <style type="text/css">
          @namespace xf url("http://www.w3.org/2002/xforms");
          body {font-family:Helvetica, sans-serif}
          .strong {font-weight:bold;}
          /* this puts everything under the repeat element into a single line */
          xf|repeat * {display:inline;}
       </style>
       <xf:model>
          <xf:instance xmlns="" id="current-synset">
            <data>
               <synset-id>3</synset-id>
               <synonym>
                   <preferred>false</preferred>
                   <syn-name>Boolean-Value</syn-name>
               </synonym>
                <synonym>
                   <preferred>false</preferred>
                   <syn-name>Conditional-Value</syn-name>
               </synonym>
               <synonym>
                   <preferred>false</preferred>
                   <syn-name>Flag</syn-name>
               </synonym>
                <synonym>
                   <preferred>true</preferred>
                   <syn-name>Indicator</syn-name>
               </synonym>
                <synonym>
                   <preferred>false</preferred>
                   <syn-name>Yes/No-Value</syn-name>
               </synonym>
            </data>
          </xf:instance>
       </xf:model>
    </head>
    <body>
       <h3>Synonym Set</h3>
       <span>(preferred term is bold)</span><br/>
       <xf:label>Synonyms: </xf:label>
          <xf:repeat nodeset="instance('current-synset')/synonym" id="repeat">
             <xf:group ref=".[preferred='true']">
                <xf:output ref="syn-name" class="strong"/>
             </xf:group>
              <xf:group ref=".[preferred='false']">
                <xf:output ref="syn-name"/>
             </xf:group>  
          </xf:repeat>
    </body>
</html>

Discussion[edit]

XForms 1.1 also includes the if attribute. Some XForms can conditionally use this for display of elements.


Next Page: Formatting Numbers | Previous Page: Repeat

Home: XForms



Formatting Numbers

Motivation[edit]

You want the view portion of your form to add formatting information to numbers. For example you want your US currency to be stored in the model as 12345.6789 but the view to display at $12,345.68. Note that the dollar sign is used as a prefix, commas are added and the decimal is rounded to two digits.

Ideally, we would like to use a simple CSS function to indicate that all currency should be formatted using the standard number picture formats such as "$#,###.##".

Method[edit]

If all browsers supported the XPath 2.0 format-number() function, this would be trivial. Till then the developer will need to resort to workaround such as using JavaScript and the XML Binding language (XBL).

Sample Code[edit]

<xf:bind nodeset="instance('invoice')/Total" calculate="round((instance('invoice')/Tax + instance('invoice')/SubTotal) * 100) div 100"/>

References[edit]

Mozilla page on XForms custom controls

The following discussions on the XForms mailing lists might be helpful.

Dan McCreary's Post to the Mozilla XForms discussion group

John Boyer's Comments on Number Formatting in XForms

acknowledgement of the currency format needs in the 2001 working draft of XForms

Next Page: Output and Links | Previous Page: Conditional Styling

Home: XForms



Output and Links

Motivation[edit]

You want to display a repeated set of URLs in a section of your form. Each URL is created by concatenating a base URL and a URL parameter.

Method[edit]

The equivalent of the HTML anchor tag (<a>) in an XForms application is the <xf:load> element.

If in a web page, you want your output to appear like this:

<div class="links">
   <a href="http://www.example.com/myservice.xq?id=1">One</a>
   <a href="http://www.example.com/myservice.xq?id=2">Two</a>
   <a href="http://www.example.com/myservice.xq?id=3">Three</a>
</div>

in an XForms application each anchor will be xf:load.

Your input instance is like the following:

<xf:instance id="link-items" xmlns="">
<data>
   <item>
      <id>1<id>
      <label>One</label>
   </item>
   <item>
      <id>2<id>
      <label>Two</label>
   </item>
   <item>
      <id>3<id>
      <label>Three</label>
   </item>
</data>
</xf:instance>

Discussion[edit]

With XForms it is not possible to create dynamic links inside a repeat using a combination of output, value and concat. This would also impact the ability to notify the user that is navigating away from a form.

There are two ways to display a list of links. Both use a trigger with the button appearance turned off. The first uses a load after setting a temporary instance. The second uses a submit/submission combination.

Using load[edit]

You can also use the load element as the element.

<xf:instance id="URL-container" xmlns="">
   <URL/>
</xf:instance>
  <!-- ... -->
  <xf:trigger appearance="minimal">
    <xf:label>One</xf:label>
    <xf:action ev:event="DOMActivate">
      <xf:setvalue ref="instance('URL-container')"
                   value="concat('http://www.example.com/my-view.xq?id=', id)"/>
      <xf:load ref="instance('URL-container')"/>
    </xf:action>
  </xf:trigger> 
<xf:instance>

Link to XForms Application[edit]

Load XForms Application

Sample Program[edit]

The following program displays a list of links in a horizontal row. Each link has a label and a URL suffix that is extracted from an instance document.

<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>
        <title>Displaying Links in an XForms Application</title>
        <style type="text/css">
          @namespace xf url("http://www.w3.org/2002/xforms");
          body {font-family:Helvetica, sans-serif}
          .links xf|repeat * {display: inline;}
          .url {color: blue; text-decoration:underline; margin: 0 2px;}
       </style>
        <xf:model>
            <xf:instance xmlns="" id="links">
                <data>
                    <link>
                        <label>XForms</label>
                        <wikipedia-id>XForms</wikipedia-id>
                    </link>
                    <link>
                        <label>XQuery</label>
                        <wikipedia-id>XQuery</wikipedia-id>
                    </link>
                    <link>
                        <label>XSLT</label>
                        <wikipedia-id>XSL Transformations</wikipedia-id>
                    </link>
                    <link>
                        <label>XML Database</label>
                        <wikipedia-id>XML_database</wikipedia-id>
                    </link>
                    <link>
                        <label>Declarative Programming</label>
                        <wikipedia-id>Declarative_programming</wikipedia-id>
                    </link>
                    <link>
                        <label>Functional Programming</label>
                        <wikipedia-id>Functional_programming</wikipedia-id>
                    </link>
                </data>
            </xf:instance>
            <xf:instance id="URL-container" xmlns="">
                <URL />
            </xf:instance>
        </xf:model>
    </head>
    <body>
        <h3>Displaying Links in an XForms Application</h3>
        <div class="links">
            <xf:repeat nodeset="instance('links')/link" id="link-repeat">
                <xf:trigger submission="replace-form-with" appearance="minimal" class="url">
                    <xf:label>
                        <xf:output ref="label" />
                    </xf:label>
                    <xf:hint>
                        <xf:output ref="wikipedia-id" />
                    </xf:hint>
                    <xf:action ev:event="DOMActivate">
                        <xf:setvalue ref="instance('URL-container')" value="concat('http://en.wikipedia.org/wiki/', instance('links')/link[index('link-repeat')]/wikipedia-id)" />
                        <xf:load ref="instance('URL-container')" />
                    </xf:action>
                </xf:trigger>
            </xf:repeat>
        </div>
    </body>
</html>

Acknowledgment[edit]

This solution was posted to the Mozilla XForms development newsgroup by John Clark on February 27th, 2008.

Using Submit and Submission for Links[edit]

As an alternative strategy you can replace a form by using the submission statement with a replace="all" attribute. You can then style the submission button using appearance="minimal" and make the button look like a link:

   <style type="text/css">
   @namespace xf url("http://www.w3.org/2002/xforms");
   .url {color: blue; text-decoration:underline; margin: 0 2px;}
   </style>
   ...
   <xf:submission id="replace-form-with" method="get"
      ref="instance('link-items')/item[index('link-repeat')]/id"
          action="http://www.example.com/my-view.xq" 
          replace="all" />
   ...
   <xf:repeat nodeset="instance('link-items')/item" id="link-repeat">
   <xf:submit submission="replace-form-with" appearance="minimal" class="url">
        <xf:label><xf:output ref="label"/></xf:label>
   </xf:submit>

The only disadvantage of this solution over using standard links is that the URL does not display in the status bar. This problem can be mitigated by using the xf:hint element within the label. This text will display when the user hovers over the link.

This method also allows you to interrupt the submission, check for changes in instance data and display warning messages before a form is unloaded.

Next Page: Switch and Case | Previous Page: Formatting Numbers

Home: XForms



Switch and Case

Motivation[edit]

You want to conditionally display different areas of the screen based on static IDs.

Screen Image[edit]

XForms-switch-case.jpg

As you click on one of the three buttons on the top row, the view displayed below will change.

Link to XForms Application[edit]

Switch and Case

Sample Program[edit]

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:xf="http://www.w3.org/2002/xforms"
 xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Switch, case and toggle</title>
      <!-- Demonstration of switch/case and toggle -->
      <style type="text/css">
      <![CDATA[
      @namespace xf url("http://www.w3.org/2002/xforms");
      xf|group {
         border: solid black 2px;
         background-color: silver;
         height: 100px;
      }
      xf|group xf|label {
         position: relative;
         font-family: Helvetica, sans-serif;
         font-weight: bold;
         background-color: white;
         padding: 2px;
         top: -10px;
         left: 10px;
      }
      xf|group p {
         position: relative;
         top: -30px;
         padding: 5px;
      }
          ]]>
      </style>
      <xf:model />
   </head>
   <body>
      <xf:trigger>
         <xf:label>View One</xf:label>
         <xf:toggle case="case-1" ev:event="DOMActivate" />
      </xf:trigger>
      <xf:trigger>
         <xf:label>View Two</xf:label>
         <xf:toggle case="case-2" ev:event="DOMActivate" />
      </xf:trigger>
      <xf:trigger>
         <xf:label>View Three</xf:label>
         <xf:toggle case="case-3" ev:event="DOMActivate" />
      </xf:trigger>
      <br />
      <br />
      <!-- only a single group will be displayed at any time -->
      <xf:switch>
         <xf:case id="case-1">
            <xf:group>
               <xf:label>View One</xf:label>
               <p>One One One One One One One One One One One One One One One One One One</p>
            </xf:group>
         </xf:case>
         <xf:case id="case-2">
            <xf:group>
               <xf:label>View Two</xf:label>
               <p>Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two</p>
            </xf:group>
         </xf:case>
         <xf:case id="case-3">
            <xf:group>
               <xf:label>View Three</xf:label>
               <p>Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three</p>
            </xf:group>
         </xf:case>
      </xf:switch>
   </body>
</html>

Discussion[edit]

XForms provides an easy ways to swap between views. This also shows how the XForms group and label can be used like the HTML fieldset and legend.

References[edit]

Next Page: Relevant | Previous Page: Output and Links

Home: XForms



Relevant

Using Bind with the Relevant Attribute[edit]

XForms also allows you to conditionally display part of a form based on some value in your instance data. Typically this is used when the answer to one field of the form conditionally displays another part.

The format of this is to use the xf:bind statement within in the xf:model.

<xf:model>
   <xf:bind nodeset="NodeYowWantToConditionallyDisplay" relevant="XPathExpression"/>
</xf:model>

The following examples demonstrate this.

Link to Relevancy XForms Application[edit]

Relevancy Demos Note: RelevancySelector.xhtml in the example application is incomplete.

Bind to a Decimal[edit]

In the following example, the second input field is conditionally displayed based on the integer value of the first instance value.

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <title>Testing the XForms bind relevant attribute.</title>
   <head>
   <xf:model>
      <xf:instance>
         <var xmlns="">
            <first>1</first>
            <second>This is the second value</second>
         </var>
      </xf:instance>
      <xf:bind nodeset="/var/first" type="xs:decimal" />
      <xf:bind nodeset="/var/second" relevant="/var/first &gt; 0" />
   </xf:model>
   </head>
   <body>
      <p>Demonstration of relevant fields.</p>
      <xf:select1 ref="/var/first" >
         <xf:label>Should I show the second question? </xf:label>
         <br />
         <xf:item select="yes">
            <xf:label>Yes Please!</xf:label>
            <xf:value>1</xf:value>
         </xf:item>
         <xf:item>
            <xf:label>No Thank You</xf:label>
            <xf:value>0</xf:value>
         </xf:item>
      </xf:select1>
      <br />
      <xf:input ref="/var/second">
         <xf:label>Second value: </xf:label>
      </xf:input>
   </body>
</html>

Using Multiple Predicates in Binds[edit]

Sometimes you have a sequence of many items and the display of one item depends on the values of other items. Predicates are a way of appending AND/OR operations to the end of a path expression used as a relevancy expression.

The following example uses a bind with two predicates. The second item in a sequence is bound to the first item. To do this you must select the second item item[2] in the nodeset and add [. > 2.0] to end of the item[1] predicate.

<html
   xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <head>
      <xf:model>
         <xf:instance id="instanceData">
            <data xmlns="">
               <item>0.00</item>
               <item>0.00</item>
            </data>
         </xf:instance>
         <!-- this rule will only allow the second item to be displayed if the first value is over 2.0 -->
         <xf:bind nodeset="instance('instanceData')/item[2]" relevant="instance('instanceData')/item[1][. &gt; 2.0]" />
      </xf:model>
   </head>
   <body>
      <xf:input ref="instance('instanceData')/item[1]">
         <xf:label>First item: </xf:label>
      </xf:input>
      <br />
      <xf:input ref="instance('instanceData')/item[2]">
         <xf:label>Second item: </xf:label>
      </xf:input>
   </body>
</html>

Bind to Boolean[edit]

Since parts of a form are usually either visible or not visible, it is natural to use a boolean value to determine if the field should be displayed.

In this example if InputIndicator is true, the second output instance is visible.

If the InputIndicator is false, the second output is not visible.

Note that expression .='true' is used. This is a string comparison. Ideally you would just be able to test a node using mynoode=true() but I have had problems with this method.

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:xf="http://www.w3.org/2002/xforms" 
  xmlns:ev="http://www.w3.org/2001/xml-events" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <head>
      <title>Example of binding to to boolean controls</title>
   </head>
   <body>
      <xf:model id="model">
         <xf:instance id="input">
            <DataIn xmlns="">
               <InputIndicator>false</InputIndicator>
            </DataIn>
         </xf:instance>
         <!-- make the input data type be a XML Schema type boolean -->
         <xf:bind id="input_bind" nodeset="/DataIn/InputIndicator" type="xs:boolean"></xf:bind>
         <!-- second instance bound to outputs -->
         <xf:instance id="output">
            <DataOut xmlns="">
               <OutputValue>Hello World!</OutputValue>
            </DataOut>
         </xf:instance>
         <!-- if the input is true, then the output is relevent -->
         <xf:bind id="output_bind" nodeset="instance('output')/OutputValue" relevant="instance('input')/InputIndicator[.='true']"/>
      </xf:model>
      <p>
         <xf:input bind="input_bind">
            <xf:label>Check to see the value of output: </xf:label>
         </xf:input>
     <br/>
         <xf:output bind="output_bind">
            <xf:label>Value of Output: </xf:label>
         </xf:output>
      </p>
   </body>
</html>

In this example, a simple checkbox is used to conditionally display a field.

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <title>Testing the relevant attribute of the bind element with boolean values.</title>
   <xf:model>
      <xf:instance>
         <var xmlns="">
            <first>true</first>
            <second/>
         </var>
      </xf:instance>
      <xf:bind nodeset="/var/first" type="xs:boolean" />
      <xf:bind nodeset="/var/second" relevant="/var/first='true'" />
   </xf:model>
   <body>
      <p>The input field should only display if the first value is checked.</p>
      <xf:input ref="/var/first">
         <xf:label>Display the next input?: </xf:label>
      </xf:input>
      <br />
      <xf:input ref="/var/second">
         <xf:label>Display this only if the first answer is true: </xf:label>
      </xf:input>
   </body>
</html>

In this example the type cast to boolean does not have any impact since relevant="/var/first=true()" does not work as expected. String comparison must be used.

Binding a view to a select 1[edit]

This example shows how to conditionally display a view based on the value of a select1 control.

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <title>Testing the XForms bind relevant attribute based on a select1 control.</title>
   <xf:model>
      <xf:instance>
         <data xmlns="">
            <select1value>1</select1value>
            <view1 />
            <view2 />
            <view3 />
         </data>
      </xf:instance>
      <xf:bind nodeset="/data/select1value" type="xs:decimal" />
      <xf:bind nodeset="/data/view1" relevant="/data/select1value = 1" />
      <xf:bind nodeset="/data/view2" relevant="/data/select1value = 2" />
      <xf:bind nodeset="/data/view3" relevant="/data/select1value = 3" />
   </xf:model>
   <body>
      <p>Demonstration of relevant fields.</p>
      <xf:select1 ref="/data/select1value">
         <xf:label>What view would you like to see? </xf:label>
         <br />
         <xf:item select="yes">
            <xf:label>View 1</xf:label>
            <xf:value>1</xf:value>
         </xf:item>
         <xf:item>
            <xf:label>View 2</xf:label>
            <xf:value>2</xf:value>
         </xf:item>
          <xf:item>
            <xf:label>View 3</xf:label>
            <xf:value>3</xf:value>
         </xf:item>
      </xf:select1>
      <br />
      <xf:input ref="/data/view1">
         <xf:label>First view: </xf:label>
      </xf:input>
      <xf:input ref="/data/view2">
         <xf:label>Second view: </xf:label>
      </xf:input>
      <xf:input ref="/data/view3">
         <xf:label>Third view: </xf:label>
      </xf:input>
   </body>
</html>

Note that the functionally is similar to a <xf:switch> and <xf:case> combination but no <xf:toggle> is used.

The bind statement[edit]

The following line is the line that does the actual bind. You should use the instance() function whenever you are binding one instance to another.

Also note that you must compare the text of the InputIndicator (the period) to true and not the InputIndicator itself.

<xf:bind id="output_bind"
   nodeset="instance('output')/OutputValue"
   relevant="instance('input')/InputIndicator[.='true']" />

An Architecture for Conditional Views and User-Maintainable Rules[edit]

Sometimes you need to have a consistent way of conditionally displaying views in a form. For example, if you want non-programmers to maintain the business logic of when a view is displayed, the binding rules to a view can be generated by an external rules engine.

To make this work you need to create a central instance that is used to control form views:

<xf:instance id="views" xmlns="">
   <data>
      <named-view-1/>
      <named-view-2/>
      <named-view-3/>
   </data>
</xf:instance>

We call this architecture one of "Named Views" because an external tool can be used to state the rules of how any named view is rendered. This will be a central location in the form that generates the view instance and the binding expressions.

Each view is wrapped in a group element that binds the group to the instance in the view:

<xf:group ref="instance('views')/named-view-1">
   <!-- these elements will be conditionally displayed based on the relevancy of named-view-1 -->
</xf:group>

<xf:group ref="instance('views')/named-view-2">
   <!-- these elements will be conditionally displayed based on the relevancy of named-view-2 -->
</xf:group>

<xf:group ref="instance('views')/named-view-2">
   <!-- these elements will be conditionally displayed based on the relevancy of named-view-3 -->
</xf:group>

The display rules for each view can then be stored in a bind statement:

<xf:bind nodeset="instance('views')/named-view-1" relevant="XPath-expression-that-returns-a-boolean-for named-view-1"/>
<xf:bind nodeset="instance('views')/named-view-2" relevant="XPath-expression-that-returns-a-boolean-for named-view-2"/>
<xf:bind nodeset="instance('views')/named-view-3" relevant="XPath-expression-that-returns-a-boolean-for named-view-3"/>

Each form can then have a "rules file" that looks similar to the following:

<form-rules-file>
   <form-id>my-form-ver-2</form-id>
   <display-rule>
      <named-view>named-view-1</named-view>
      <xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-1</xpath-expression>
   </display-rule>
   <display-rule>
      <named-view>named-view-2</named-view>
      <xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-2</xpath-expression>
   </display-rule>
   <display-rule>
      <named-view>named-view-2</named-view>
      <xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-3</xpath-expression>
   </display-rule>
</form-rules-file>

You can then build another XForms application that allows non-programmers to maintain these rules files and and a simple transform that places the instance and bind statements in the XForms model when it is loaded. The original groups may still need to be manually added to the form but once the views are added the rules can be maintained with a separate application.

Changing Fields to Display[edit]

The following example conditionally displays two zip code fields if the country code is 'usa" or displays a postal code if the field is not 'usa'.

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <head>
        <title>Testing the XForms bind relevant attribute.</title>
        <style language="text/css">
            <![CDATA[
    @namespace xf url("http://www.w3.org/2002/xforms");

     /* this allows the descenders (jpqy) to be visible in the drop down list */
     xf|select1 .xf-value {height: 1.5em;} 
     
     .ZipCode .xf-value {width:5ex}
     .ZipCodeSuffix .xf-value {width:4ex}
     .PostalCode .xf-value {width:10ex}
    ]]>
        </style>
        <xf:model>
            <xf:instance xmlns="" id="save-data">
                <data>
                    <CountryCode>usa</CountryCode>
                    <ZipCode>12345</ZipCode>
                    <ZipCodeSuffix>1234</ZipCodeSuffix>
                    <PostalCode>AB-1234</PostalCode>
                </data>
            </xf:instance>
            
            <!-- The views instance are boolean values that tell what fields are visible -->
            <xf:instance xmlns="" id="views">
                <data>
                    <DisplayZipCode/>
                    <DisplayPostalCode/>
                </data>
            </xf:instance>
            
            <!-- this rule only displays the zip code if the country code is 'usa'-->
            <xf:bind id="DisplayZipCode"
                nodeset="instance('views')/DisplayZipCode" 
                relevant="instance('save-data')/CountryCode='usa'" />
            <xf:bind id="DisplayPostalCode"
                nodeset="instance('views')/DisplayPostalCode" 
                relevant="not(instance('save-data')/CountryCode='usa')" />
            
        </xf:model>
    </head>
    <body>
        <p>Demonstration of binding Zip Code Input</p>
        
        <xf:select1 ref="instance('save-data')/CountryCode" selection="open">
            <xf:label>Country:</xf:label>
            <xf:item>
                <xf:label>USA</xf:label>
                <xf:value>usa</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Canada</xf:label>
                <xf:value>can</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Mexico</xf:label>
                <xf:value>mex</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>Other</xf:label>
                <xf:value>other</xf:value>
            </xf:item>
        </xf:select1>
        <br/>
        
        <xf:group bind="DisplayZipCode">
            <xf:input ref="instance('save-data')/ZipCode" class="ZipCode">
                <xf:label>Zip Code: </xf:label>
            </xf:input>
            <xf:input ref="instance('save-data')/ZipCodeSuffix" class="ZipCodeSuffix">
                <xf:label>-</xf:label>
            </xf:input>
        </xf:group>
        <xf:input ref="instance('save-data')/LocationPostalID" bind="DisplayPostalCode" class="DisplayPostalCode">
            <xf:label>Postal Code: </xf:label>
        </xf:input>
    </body>
</html>

Delete[edit]

One of the most common occurrence of conditional display is the delete function for repeating elements. Typically you do not want to delete the last one. See the XForms/Conditional_delete example.

Discussion[edit]

Next Page: Show-Hide Controls | Previous Page: Switch and Case

Home: XForms



Binding in Repeats

Motivation[edit]

You have a list of items and you want a simple way of conditionally displaying fields within a repeated group.

Method[edit]

We will do this is two ways. First we will use a bind expression in the model. The second method of doing this will be to use a group element with a ref attribute.

Sample Data[edit]

<data xmlns="">
    <group>
        <code>yes</code>
        <field>display 1</field>
    </group>
    <group>
       <code>no</code>
       <field>display 2</field>
    </group>
    <group>
       <code>yes</code>
       <field>display 3</field>
    </group>
</data>

Sample Repeat[edit]

<xf:repeat nodeset="instance('my-data')/group" id="my-repeat">
     <fieldset>

         <legend>
             Group # <xf:output value="count(preceding-sibling::*) +1"></xf:output>
         </legend>

         <xf:select1 ref="code">
             <xf:label>Display Input Field: </xf:label>
             <xf:item>
                 <xf:label>Yes</xf:label>
                 <xf:value>yes</xf:value>
             </xf:item>
             <xf:item>
                 <xf:label>No</xf:label>
                 <xf:value>no</xf:value>
             </xf:item>
         </xf:select1>
         
         
         <xf:input ref="field" >
             <xf:label>Conditional Display: </xf:label>
         </xf:input>
         
     </fieldset>
</xf:repeat>

Solution Using Relative Binds[edit]

In this example we use a relative statement to indicate that the field should only be displayed if the code value is "yes". Note that the context of the relevant expression is the result of each nodeset item.

<xf:bind id="field" 
   nodeset="instance('my-data')/group/field"
   relevant="../code = 'yes'"/>

Solution Using Group Element[edit]

We can use the ref attribute to conditionally display any field within a repeat. We do this by starting the group ref attribute with "." to give it the current context. Then we add a predicate to turn on or off that entire group. In this case if the code is "yes" the input field will be displayed. If it is not the field will be hidden.

<xf:group ref=".[code='yes']">
   <xf:input ref="field">
      <xf:label>Conditional Display: </xf:label>
    </xf:input>
</xf:group>

Complete Example[edit]

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
        <title>Binds in Repeats</title>
        <style type="text/css">
            @namespace xf url("http://www.w3.org/2002/xforms");
            body {{
                font-family:Helvetica, sans-serif;
            }}</style>
        <xf:model>
            <xf:instance id="my-data">
                <data xmlns="">
                    <group>
                        <code>yes</code>
                        <field>display 1</field>
                    </group>
                    <group>
                        <code>no</code>
                        <field>display 2</field>
                    </group>
                    <group>
                        <code>yes</code>
                        <field>display 3</field>
                    </group>
                    <group>
                        <code>no</code>
                        <field>display 4</field>
                    </group>
                </data>
            </xf:instance>
            
            
            <xf:bind id="field" 
                nodeset="instance('my-data')/group/field"
                relevant="../code = 'yes'"/>
                
            
        </xf:model>
    </head>
    <body>
        <h1>Test of binding rules within a repeat</h1>
        <xf:repeat nodeset="instance('my-data')/group" id="my-repeat">
             <fieldset>
                 <legend>
                     Group # <xf:output value="count(preceding-sibling::*) +1"></xf:output>
                 </legend>
                 <xf:select1 ref="code">
                     <xf:label>Display Input Field: </xf:label>
                     <xf:item>
                         <xf:label>Yes</xf:label>
                         <xf:value>yes</xf:value>
                     </xf:item>
                     <xf:item>
                         <xf:label>No</xf:label>
                         <xf:value>no</xf:value>
                     </xf:item>
                 </xf:select1>
                 
                 
                 <xf:input ref="field" >
                     <xf:label>Conditional Display: </xf:label>
                 </xf:input>
                 
             </fieldset>
        </xf:repeat>
        
        <xf:output value="index('my-repeat')">
            <xf:label>Current Selected Group: </xf:label>
        </xf:output>
    </body>
</html>



Show-Hide Controls

Motivation[edit]

You want to only display a full representation of a control when the user wants to set or change the control's value.

Method[edit]

We will use the switch/case and toggle elements to conditionally display a custom control. When the user opens a form a small "show value" of this control is visible and a trigger to set or change the value of the control. After the user selects a value the control reverts to a view that minimizes the screen area.

Screen Images[edit]

There are two ways that this control is viewed. The first takes only a small areas of the form and is a read-only view. It shows all the current values of the months selected.

XForms Control Hidden

When the users select the "Set Months" trigger the full control is made visible. When you are done setting the months the control is set back to the hidden mode.

XForms Control Visible

Sample Code[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
    <head>
        <title>Show/Hide Control</title>
        <!-- Demonstration of show/hide of a control -->
        <style type="text/css">
            @namespace xf url("http://www.w3.org/2002/xforms");
            body {font-family: Helvetica, sans-serif;}
            xf|output > xf|label, xf|select > xf|label {font-weight: bold;}
        </style>
        <xf:model>
            <xf:instance xmlns="" id="save-data">
                <data>
                    <month-code>January May November</month-code>
                </data>
            </xf:instance>
            <xf:instance xmlns="" id="code-table">
                <data>
                    <month-code>January</month-code>
                    <month-code>February</month-code>
                    <month-code>March</month-code>
                    <month-code>April</month-code>
                    <month-code>May</month-code>
                    <month-code>June</month-code>
                    <month-code>July</month-code>
                    <month-code>August</month-code>
                    <month-code>September</month-code>
                    <month-code>October</month-code>
                    <month-code>November</month-code>
                    <month-code>December</month-code>
                </data>
            </xf:instance>
        </xf:model>
    </head>
    <body>
        <xf:switch>
            <!-- initially, only the label and the read-only value is visible in the first case -->
            <xf:case id="hide">
                <xf:output ref="instance('save-data')/month-code">
                    <xf:label>Current Months:</xf:label>
                </xf:output>
                <xf:trigger>
                    <xf:label>Set Months</xf:label>
                    <xf:toggle case="unhide" ev:event="DOMActivate" />
                </xf:trigger>
            </xf:case>
            <!-- if you click on the trigger called "Set Months" the full control will be visible -->
            <xf:case id="unhide">
                <xf:select ref="instance('save-data')/month-code" appearance="full">
                   <xf:label>Select Months</xf:label>
                   <xf:itemset nodeset="instance('code-table')/month-code">
                      <xf:label ref="."/>
                      <xf:value ref="."/>
                   </xf:itemset>
                </xf:select>
                <!-- once you have selected all the months in the control you can hide the control again -->
                <xf:trigger>
                    <xf:label>Hide</xf:label>
                    <xf:toggle case="hide" ev:event="DOMActivate" />
                </xf:trigger>
            </xf:case>
        </xf:switch>
    </body>
</html>

Next Page: Disable Buttons | Previous Page: Relevant

Home: XForms



Disable Buttons

Motivation[edit]

You want to remove a delete button to prevent removal of the last item of a list.

Method[edit]

Create a binding rule in the model that only allows the button to be displayed if there are two or more elements.

This is very common when you have a "Delete" button that must not be visible if there is only one item in a list left.

One approach is to use the "ref" attribute of each trigger to only display if there are more than one item:

<xf:trigger ref="self::node()[count(../name) &gt; 1]">
   <xf:label>Delete Classifier</xf:label>
   <xf:delete ev:event="DOMActivate" nodeset="instance('save-data')/name" at="index('name-repeat')"/>            
</xf:trigger>

This would count the number of classifiers and display the "delete" button.

<data>
  <name>John</name>
  <name>Fred</name>
  <name>Sue</name>
</data>

Here is an example of this rule:

<xf:bind id="triggerDisplay" nodeset="display-delete" relevant="count(/data/person) &gt; 1"/>

The above uses the XPath count() function with the greater than operator. But since it must be escaped you must use the "&gt;" instead of ">".

Or alternatively the delete button is only visible if the second person record exists in the instance.

<xf:bind id="triggerDisplay" nodeset="display-delete" relevant="/data/person[2]"/>

This gets around having to count all the elements and doing a comparison. So it is a little bit more efficient for longs lists of items.

This creates a rule call "triggerDisplay" that pin relevancy to an XForms instance.

Screen Image[edit]

Form without Delete button
Form with Delete button visible

Link to XForms Application[edit]

Load XForms Application

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
     <title>Disable Delete</title>
     <xf:model>
       <xf:instance id="myInstance" xmlns="">
         <data>
           <person>
             <name>John Doe</name>
           </person>
           <display-delete/>
         </data>
       </xf:instance>
       <!-- only display the delete button if there is more than one person -->
       <xf:bind id="triggerDisplay" nodeset="display-delete"
            relevant="count(/data/person) &gt; 1"/>
         <xf:submission id="mySubmission" method="post"
            action="http://www.xformstest.org/cgi-bin/echo.sh"/>
     </xf:model>
   </head>
   <body>
     <h2>Demo of Button Disable</h2>
     <xf:repeat nodeset="person">
       <xf:input ref="name">
         <xf:label>Name: </xf:label>
       </xf:input>
     </xf:repeat>
     <hr/>
     <xf:trigger>
       <xf:label>Insert</xf:label>
       <xf:insert nodeset="instance('myInstance')/person"
            at="last()" position="after" ev:event="DOMActivate"/>
     </xf:trigger>
     <!-- This trigger is bound to the display rule -->
     <xf:trigger bind="triggerDisplay">
       <xf:label>Delete</xf:label>
       <xf:delete nodeset="instance('myInstance')/person"
           at="last()" ev:event="DOMActivate"/>
     </xf:trigger>
     <xf:submit submission="mySubmission">
       <xf:label>Submit instance</xf:label>
     </xf:submit>
   </body>
</html>

Using the Context attribute[edit]

You can also use the context attribute of the trigger to tell it when to fire.

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:xf="http://www.w3.org/2002/xforms"
     xmlns:ev="http://www.w3.org/2001/xml-events">

     <head>
          <title>Disable final delete trigger.</title>
          <xf:model id="person">
               <xf:instance id="person_xml" xmlns="">
                    <person>
                         <contacts>
                              <section name="Personal">
                                   <contact/>
                              </section>
                         </contacts>
                    </person>
               </xf:instance>
          </xf:model>
     </head>
     <body>
          <xf:repeat nodeset="contacts/section" id="repeat_section">
               <fieldset>
                    <legend>
                         <xf:trigger>
                              <xf:label>-</xf:label>
                              <xf:hint>Delete this section.</xf:hint>
                              <xf:delete
                                   context="instance('person_xml')/contacts"
                                   nodeset="section[position()!=last()]"
                                   at="index('repeat_section')"
                                   ev:event="DOMActivate"/>
                         </xf:trigger>
                         <xf:input ref="./@name">
                              <xf:label>section name</xf:label>
                         </xf:input>
                    </legend>
                    <xf:repeat nodeset="contact" id="repeat_contact">
                         <xf:input ref=".">
                              <xf:label>contact</xf:label>
                         </xf:input>
                         <xf:trigger>
                              <xf:label>-</xf:label>
                              <xf:hint>Delete this contact.</xf:hint>
                              <xf:delete
                                   context="instance('person_xml')/contacts/section[index('repeat_section')]"
                                   nodeset="contact[position()!=last()]"
                                   at="index('repeat_contact')"
                                   ev:event="DOMActivate"/>                
                         </xf:trigger>
                         <xf:trigger>
                              <xf:label>+</xf:label>
                              <xf:hint>Add a new contact after this one.</xf:hint>
                              <xf:insert nodeset="." at="index('repeat_section')" position="after" ev:event="DOMActivate"/>
                         </xf:trigger>
                    </xf:repeat>
               </fieldset>
               <xf:trigger>
                    <xf:hint>Add a new section after this one.</xf:hint>
                    <xf:label>add section</xf:label>
                    <xf:insert nodeset="." at="last()" position="after" ev:event="DOMActivate"/>
               </xf:trigger>
          </xf:repeat>
     </body>
</html>

Context[edit]

XForms 1.1 Specification

Optional XPath expression used to change the in-scope evaluation context for the delete element. This attribute is ignored if the bind attribute is provided. If the attribute is not given, then the default delete context is the in-scope evaluation context. Otherwise, the XPath expression is evaluated using the in-scope evaluation context, and the first node rule is applied to obtain the delete context. The delete action is terminated with no effect if the delete context is the empty node-set or if the context attribute is not given and the Node Set Binding node-set is empty.

Example of Min and Max[edit]

The following disables both the Delete and Add triggers when the number of items approaches the minimum and maximum range.

In this case the XML Schemas for the Person element was the follows:

<xs:element name="Phone" minOccurs="2" maxOccurs="5">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Phone Number Demo</title>
      <!-- used to demonstract the steps in autogeneration of XML Schemas that have repeating items -->
      <link rel="stylesheet"  type="text/css" href="person-phone.css"/>
      <xf:model>
         <xf:instance xmlns="" src="../test-input-instances/22-two-to-five-repeats.xml" id="phones"/>
         
         <!-- views are areas of the screen that are conditionally displayed -->
         <xf:instance xmlns="" id="views">
              <data>
                 <phone-delete-trigger/>
                 <phone-add-trigger/>
              </data>
         </xf:instance>
         
           <!-- only display the trigger if we have a second phone number -->
            <xf:bind id="phone-delete-trigger" 
            nodeset="instance('views')/phone-delete-trigger" 
            relevant="instance('phones')/Phone[3]"/>
            <xf:bind id="phone-add-trigger" 
            nodeset="instance('views')/phone-add-trigger" 
            relevant="count(instance('phones')/Phone) &lt; 5"/>

          <xf:submission id="save" method="post" action="save.xq" replace="all"/>
      </xf:model>
   </head>
   <body>

      <xf:label class="group-label">Phone Numbers</xf:label>
          <xf:repeat id="phone-number-repeat" nodeset="/PersonPhones/Phone">
                <xf:input ref="PhoneDescriptionText" class="PhoneDescriptionText"  id="PhoneDescriptionText"/>
                <xf:input ref="PhoneNumber" class="PhoneNumber"/>
              
              <!-- bind="phone-delete-trigger" -->
              <xf:trigger bind="phone-delete-trigger">
                  <xf:label>Delete</xf:label>
                  <!-- this deletes the currently selected phone number -->
                  <xf:delete nodeset="instance('phones')/Phone[index('phone-number-repeat')]" ev:event="DOMActivate"/>
              </xf:trigger>
              
          </xf:repeat>
          <xf:trigger bind="phone-add-trigger">
              <xf:label>Add</xf:label>
              <xf:action ev:event="DOMActivate">
                  <xf:insert nodeset="instance('phones')/Phone" at="last()" position="after"/>
                  <!-- this initialized the values of the phone number to null.  Can also use an origin attribute.   -->
                  <xf:setvalue ref="/PersonPhones/Phone[index('phone-number-repeat')]/PhoneDescriptionText" value=""/>
                  <xf:setvalue ref="/PersonPhones/Phone[index('phone-number-repeat')]/PhoneNumber" value=""/>
                  <!-- this puts the cursor in the first field of the new row we just added -->
                  <xf:setfocus control="PhoneDescriptionText"/>
              </xf:action>
          </xf:trigger>
  
    </body>
</html>


Discussion[edit]

Next Page: Read Only | Previous Page: Relevant

Home: XForms



Read Only

Motivation[edit]

Forms frequently need to display fields that are not editable by the user. The following program demonstrates this feature.

This is done in XForms using a binding and a style sheet.

A single field (or group of fields) can be marked as read-only with a single bind statement. For example, suppose you had a set of fields related to shipping supplies to remote staff in your IT department. The billing address could not be changed, only who an item was shipped to.

The following single line in the model would make all of the sub-elements of BillToAddress read-only:

<xf:bind nodeset="/PurchaseOrders/BillToAddress" readonly="true()" />

Note that because of CSS, all the fields under this binding will be marked read-only. This is one good reason you may want to logically group read-only data elements in an application.

Screen Image[edit]

XForm read-only fields have a gray background

Sample Program[edit]

XHTML XForm[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Demonstration of Read-Only Binding</title>
      <link rel="stylesheet" type="text/css" href="table-form.css" />
      <xf:model>
         <xf:instance xmlns="" src="PurchaseOrder.xml" />
         <!-- the following line sets all the data input fields under this node to be read-only -->
         <xf:bind nodeset="/PurchaseOrder/BillToAddress" readonly="true()" />
      </xf:model>
   </head>
   <body>
      <xf:group ref="/PurchaseOrder/BillToAddress">
         <xf:label class="box-label">Billing Address :</xf:label>
         <xf:input ref="OrganizationName">
            <xf:label>Organization Name: </xf:label>
         </xf:input>
         <xf:input ref="LocationStreetFullText">
            <xf:label>Street: </xf:label>
         </xf:input>
         <xf:input ref="LocationStreetFullText2">
            <xf:label />
         </xf:input>
         <xf:input ref="LocationCityName">
            <xf:label>City:</xf:label>
         </xf:input>
         <xf:input ref="LocationStateName">
            <xf:label>State:</xf:label>
         </xf:input>
         <xf:input ref="LocationPostalID">
            <xf:label>Postal Code:</xf:label>
         </xf:input>
      </xf:group>
      <xf:group ref="/PurchaseOrder/ShipToAddress">
         <xf:label class="box-label">Shipping Address :</xf:label>
         <xf:input ref="PersonName">
            <xf:label>Person Name: </xf:label>
         </xf:input>
         <xf:input ref="LocationStreetFullText">
            <xf:label>Street: </xf:label>
         </xf:input>
         <xf:input ref="LocationStreetFullText2">
            <xf:label />
         </xf:input>
         <xf:input ref="LocationCityName">
            <xf:label>City:</xf:label>
         </xf:input>
         <xf:input ref="LocationStateName">
            <xf:label>State:</xf:label>
         </xf:input>
         <xf:input ref="LocationPostalID">
            <xf:label>Postal Code:</xf:label>
         </xf:input>
      </xf:group>
   </body>
</html>

Sample Instance Data (PurchaseOrder.xml)[edit]

<PurchaseOrder xmlns="">
   <BillToAddress>
      <OrganizationName>MegaCorp IT Dept.</OrganizationName>
      <LocationStreetFullText>123 Main St.</LocationStreetFullText>
      <LocationStreetFullText2>Mailstop 47</LocationStreetFullText2>
      <LocationCityName>Anytown</LocationCityName>
      <LocationStateName>Minnesota</LocationStateName>
      <LocationPostalID>55123</LocationPostalID>
   </BillToAddress>
   <ShipToAddress>
      <PersonName>John Jones</PersonName>
      <LocationStreetFullText>123 Main Street SE</LocationStreetFullText>
      <LocationStreetFullText2>Apartment 123</LocationStreetFullText2>
      <LocationCityName>Anytown</LocationCityName>
      <LocationStateName>Minnesota</LocationStateName>
      <LocationPostalID>55123</LocationPostalID>
   </ShipToAddress>
</PurchaseOrder>

XForms tabular layout stylesheet (table-form.css)[edit]

 /* a stylesheet for tabular XForms input field alignment */

@namespace xf url("http://www.w3.org/2002/xforms");

/* give the input form labels and the fieldset legend a bold sans-serif font */
label {
   font-family: Arial, Helvetica, sans-serif;
   font-weight: bold;
   font-size: small;
}

xf|group {
	border: black solid 2px;
	padding: 5px;
	width: 300px;
}

/* the labels are right-aligned in a 150px wide column */
xf|input xf|label {
   width: 150px;
   margin: 3px;
   text-align: right;
}

/* the input values are left aligned */
xf|value {
   text-align: left;
}

/* vertical area between input boxes */
input {
   margin: .2em;        
}

/* each input is a row in the group table */
xf|input {
   display: table-row;
}

/* each label within an input is a cell in the input row */
xf|input xf|label {
   display: table-cell; 
}

/* each value (pseudo-element) is also a cell in the input row */
xf|input::value {
   display: table-cell;
}

Discussion[edit]

Next Page: Select and Group | Previous Page: Disable Buttons

Home: XForms



Select and Group

Motivation[edit]

You want to conditionally display a group of elements based on the value selected from a list. This will work similar to a "switch/case" but you can have each view depend on complex XPath expressions that will evaluated to either true or false.

Screen Image[edit]

Using bind and select1 to conditionally display a group

In the screen image above, the second item is selected. When a different item is selected, the view under the select list changes.

Sample Program[edit]

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Dynamically bind to a group</title>
      <!-- Using bind and relevant in the model to conditionally display a group -->
      <!-- Alternative to switch/case/toggle when the id of toggle is dynamically calculated -->
      <style type="text/css">
      @namespace xf url("http://www.w3.org/2002/xforms");
      xf|group {
         border: solid black 2px;
         background-color: silver;
         height: 100px;
      }
      xf|group xf|label {
         position: relative;
         font-family: Helvetica, sans-serif;
         font-weight: bold;
         background-color: white;
         padding: 2px;
         top: -10px;
         left: 10px;
      }
      xf|group p {
         position: relative;
         top: -30px;
         padding: 5px;
      }
      </style>
      <xf:model>
         <xf:instance>
            <data xmlns="">
               <current-view>one</current-view>
               <view-1>one</view-1>
               <view-2>two</view-2>
               <view-3>three</view-3>
            </data>
         </xf:instance>
         <!-- if the current-view is 'one' make the view-1 group relevent (visible)-->
         <xf:bind nodeset="view-1" relevant="../current-view= 'one'" />
         <xf:bind nodeset="view-2" relevant="../current-view = 'two'" />
         <xf:bind nodeset="view-3" relevant="../current-view = 'three'" />
      </xf:model>
   </head>
   <body>
         <xf:select1 ref="current-view">
            <xf:label>Select View: </xf:label>
            <xf:item>
               <xf:label>One</xf:label>
               <xf:value>one</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>Two</xf:label>
               <xf:value>two</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>Three</xf:label>
               <xf:value>three</xf:value>
            </xf:item>
         </xf:select1>
         <br/>
         <!-- only one of the three outputs will display -->
         <xf:output ref="view-1">
            <xf:label>Current view: </xf:label>
         </xf:output>
         <xf:output ref="view-2">
            <xf:label>Current view: </xf:label>
         </xf:output>
         <xf:output ref="view-3">
            <xf:label>Current view: </xf:label>
         </xf:output>
         <br/>
         <br/>
         <!-- only a single group will be displayed at any time -->
         <xf:group ref="view-1">
            <xf:label>View One</xf:label>
            <p>One One One One One One One One One One One One One One One One One One</p>
         </xf:group>
         <xf:group ref="view-2">
            <xf:label>View Two</xf:label>
            <p>Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two</p>
         </xf:group>
         <xf:group ref="view-3">
            <xf:label>View Three</xf:label>
            <p>Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three</p>
         </xf:group>
   </body>
</html>

Discussion[edit]

This program is very similar to the example that uses a button to toggle a switch/case but the value is calculated dynamically by any XPath expression. The prior example that uses switch/case/toggle uses an XML Event to make a specific case visible.

References[edit]

Next Page: Dynamic Labels | Previous Page: Read Only

Home: XForms



Dynamic Labels

Motivation[edit]

Sometimes you want to change a single label on a form without loading the form. For example, after you enter the country of an address you may want to ask for a "Province" in Canada or a "State" in the US. This can also be used to load alternative labels based on the user's language.

Screen Image[edit]

Examples of XForms Dynamic Labels

Link to Working XForms Application[edit]

XForms Example of Dynamic Labels

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <title>Example of Dynamic Label Lookup</title>
      <!-- based on a version by Kurt Cagle -->
      <style type="text/css">
      @namespace xf url("http://www.w3.org/2002/xforms");
      body {font-family: Ariel, Helvetica, san-serif}
      /* Input Control labels are right-aligned in a 200px wide column that floats to the left. */

/* This line ensures all the separate input controls appear on their own lines */
xf|input, xf|select, xf|select1, xf|textarea {display:block; margin:5px 0;}

/* Makes the labels right aligned in a 200px wide column that floats to the left of the input controls. */
xf|input > xf|label, xf|select > xf|label, xf|select1 > xf|label, xf|textarea > xf|label {text-align:right; padding-right:10px; width:200px; float:left; text-align:right;}

/* Put a black border and background color around all specified XForms groups and gives them both margin and padding */
xf|group {border: solid black 1px; margin:15px 5px; padding:5px; background-color:Lavender;}
.group-label {text-align:left;font-weight:bold;font-size:12pt;}
</style>
      <xf:model>
         <xf:instance id="data" xmlns="">
            <Data>
               <PersonName>
                  <PersonGivenName>John</PersonGivenName>
                  <PersonMiddleName>Paul</PersonMiddleName>
                  <PersonSurName>Doe</PersonSurName>
               </PersonName>
               <Address>
                  <LocationStreetFull>123 Main St.</LocationStreetFull>
                  <LocationCityName>Anytown</LocationCityName>
                  <LocationStateName>MN</LocationStateName>
                  <LocationPostalID>55123</LocationPostalID>
               </Address>
            </Data>
         </xf:instance>
         <xf:instance id="selected-country" xmlns="">
            <data>
               <country-id>usa</country-id>
            </data>
         </xf:instance>
         <xf:bind id="country" nodeset="instance('selected-country')/country-id" />
         <xf:instance id="label-lookup" xmlns="">
            <label-lookup>
               <country>
                  <country-id>usa</country-id>
                  <data-element name="record" label="Record" />
                  <data-element name="PersonName" label="Person Name" />
                  <data-element name="PersonGivenName" label="First (Given) Name" />
                  <data-element name="PersonSurName" label="Last (Family) Name" />
                  <data-element name="PersonMiddleName" label="Middle Name" />
                  <data-element name="Address" label="Address" />
                  <data-element name="LocationStreetFull" label="Street" />
                  <data-element name="LocationCityName" label="City" />
                  <data-element name="LocationStateName" label="State" />
                  <data-element name="LocationCountryName" label="Country" />
                  <data-element name="LocationPostalID" label="Zip" />
               </country>
               <country>
                  <country-id>canada</country-id>
                  <data-element name="record" label="Record" />
                  <data-element name="PersonName" label="Person Name" />
                  <data-element name="PersonGivenName" label="First Name" />
                  <data-element name="PersonSurName" label="Last Name" />
                  <data-element name="PersonMiddleName" label="Middle Name" />
                  <data-element name="Address" label="Address" />
                  <data-element name="LocationStreetFull" label="Street" />
                  <data-element name="LocationCityName" label="City" />
                  <data-element name="LocationStateName" label="Province" />
                  <data-element name="LocationCountryName" label="Country" />
                  <data-element name="LocationPostalID" label="Postal Code" />
               </country>
                <country>
                  <country-id>uk</country-id>
                  <data-element name="record" label="Record" />
                  <data-element name="PersonName" label="Person Name" />
                  <data-element name="PersonGivenName" label="First Name" />
                  <data-element name="PersonSurName" label="Sur Name" />
                  <data-element name="PersonMiddleName" label="Middle Name" />
                  <data-element name="Address" label="Address" />
                  <data-element name="LocationStreetFull" label="Street" />
                  <data-element name="LocationCityName" label="City" />
                  <data-element name="LocationStateName" label="County" />
                  <data-element name="LocationCountryName" label="Country" />
                  <data-element name="LocationPostalID" label="Postal Code" />
               </country>
            </label-lookup>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Demonstration of Dynamic Labels</p>
      <xf:select1 bind="country" incremental="true">
         <xf:label>Country: </xf:label>
         <xf:item>
            <xf:label>USA</xf:label>
            <xf:value>usa</xf:value>
         </xf:item>
         <xf:item>
            <xf:label>Canada</xf:label>
            <xf:value>canada</xf:value>
         </xf:item>
         <xf:item>
            <xf:label>UK</xf:label>
            <xf:value>uk</xf:value>
         </xf:item>
      </xf:select1>
      <xf:repeat nodeset="*">
         <xf:group ref=".">
            <!-- get the label for the group of elements -->
            <xf:label class="group-label">               
               <xf:output value="concat(instance('label-lookup')/country[country-id=instance('selected-country')/country-id]/data-element[string(@name)=string(name(current()))]/@label,':')" />
            </xf:label>
            <xf:repeat nodeset="*">
               <xf:input ref=".">
                  <xf:label>
                     <xf:output value="concat(instance('label-lookup')/country[country-id=instance('selected-country')/country-id]/data-element[string(@name)=string(name(current()))]/@label,':')" />
                  </xf:label>
               </xf:input>
            </xf:repeat>
         </xf:group>
      </xf:repeat>
<!-- debug 
      <xf:output bind="country">
         <xf:label>Country id:</xf:label>
      </xf:output>
-->
   </body>
</html>

Discussion[edit]

This example shows a nice clean elegant way to iterate over elements in a instance for groups and elements. The structure is:

<xf:repeat nodeset="*"> <!-- match the first level in the instance with groups-->
   <xf:group ref=".">
      <xf:repeat nodeset="*">  <!-- match the second level in the instance with inputs -->
          <xf:input ref=".">

      </xf:repeat>
   </xf:group>
</xf:repeat>


This examples shows how the output tag can be buried inside the input labels.

<xf:input ref="">
   <xf:label>
      <xf:output value=""/>
   </xf:label>
</xf:input>

Credits[edit]

This example was originally inspired by Kurt Cagle.

Next Page: Suggesting Items | Previous Page: Select and Group

Home: XForms



Suggesting Items

Motivation[edit]

You have a text field that the users types text into. You want to show a list of possible suggested items as the user types. This feature is also known as autocomplete.

Method[edit]

Use a standard input control and set the incremental="true" attribute. Use the xforms-value-changed event to trigger a submission that puts possible values in a list. When the user select a value from the suggestion list it will replace the text value in the field.

We will also add a bind rule so that the selection view will only be visible if there is at least one suggested item.

<xf:bind nodeset="instance('conditional-views')/suggest-view" 
         relevant="count(instance('suggest-results')//item) &gt; 1"/>

This program depends on a server-side REST web service that you pass in a single parameter "prefix" such as the following that returns recipe ingredients that begin with ba:

http://www.cems.uwe.ac.uk/xmlwiki/XForms/suggest-ingredient.xq?prefix=ba

This program returns an XML file that is restricted to the suggested ingredients that begin with the prefix passed to the XQuery web service:

<suggestions>
<tc>Ba</tc>
   <ingredient>Baking powder</ingredient>
   <ingredient>Bananas</ingredient>
   <ingredient>Barbecue Sauce</ingredient>
   <ingredient>Barley</ingredient>
   <ingredient>Barley, malt</ingredient>
   <ingredient>Basil</ingredient>
   <ingredient>Bass</ingredient>
   <ingredient>Bay leaves</ingredient>
</suggestions>

Screen Image[edit]

The following example shows that as the user types in the letter "c", a list of possible ingredients instantly appears in the right column. The user can continue typing and the list will be restriced to the suggestions that start with the letters typed. When the user selects an item it will fill in the prior selected field.

Suggestions displayed in the right margin of a form

Link to XForms Application[edit]

NOTE: To get this program to run you will first have to add our server to the XForms "Trusted Sites" list.

To do this in FireFox, go to your Tools/Options/Security menu and add www.cems.uwe.ac.uk and googlecode.com to your allowed sites list. This allows the form (loaded from the googlecode domain) to pull data from the server at www.cems.uwe.ac.uk.

After you do this click the link below:

Load XForms Application

Sample Program[edit]

<html xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Suggest Event Test</title>
        <style type="text/css">
           @namespace xf url("http://www.w3.org/2002/xforms");
           body {font-family: Helvetica, sans-serif}
	#suggest {
            	position: absolute;
            	top: 0;
            	margin: 0 0 0 300px;
            	width: auto;
            	border: 1px solid blue;			
	}
	#showlog {
		position: absolute;
		width: auto;
		font-size: 8pt; 
		color: SlateGray;
		background-color: lavender; 
		border: 1px solid SlateGray;			
	}
	</style>
        <xf:model>
            <xf:instance xmlns="" id="my-form">
                <data>
                    <element/>
                    <element/>
                    <element/>
                </data>
            </xf:instance>
            <xf:instance xmlns="" id="conditional-views">
                <data>
                    <suggest-view/>
                </data>
            </xf:instance>

            <!-- only show the suggested values if we have at least one suggestion -->
            <xf:bind nodeset="instance('conditional-views')/suggest-view" 
                     relevant="count(instance('suggest-results')//ingredient) &gt; 1"/>

        	<!-- this is the place that we store the parameters that are going out to the remote suggest service -->
            <xf:instance id="suggest-query">
                <query xmlns="">
                    <prefix/>
                </query>
            </xf:instance>
           
           <!-- this is where we put an ID to the calling element  -->
            <xf:instance xmlns="" id="selected-word">
                <data>
                    <calling-element/>
                </data>
            </xf:instance>
        	
           <!-- this is where we put the suggested ingredients that are returned from the server -->
           <xf:instance id="suggest-results" xmlns="">
                <suggestions/>
            </xf:instance>
           
            <!-- This sends the request to the ingredient suggestion service at the U of West England.  -->
            <!-- Please make a local copy if you are doing more than a few examples for learning XForms and XQuery -->
            <xf:submission id="get-suggestions" action="http://www.cems.uwe.ac.uk/xmlwiki/XForms/suggest-ingredient.xq" 
                method="get" separator="&amp;" 
                ref="instance('suggest-query')" 
                replace="instance" instance="suggest-results">
                <xf:action ev:event="xforms-submit">
                    <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                    <xf:setvalue ref="instance('log')/event[last()]" 
                        value="concat('getting suggestions for: ', instance('suggest-query')/prefix)"/>
                 </xf:action>
            </xf:submission>
 
           <!-- this is where we put the logging events -->
            <xf:instance id="log">
                <data xmlns="">
                    <event/>
                </data>
            </xf:instance>           
           
            <!-- put the cursor in the first field when the form becomes ready -->
            <xf:action ev:event="xforms-ready">
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'xforms-ready'"/>
                <xf:setfocus control="field-1"/>
            </xf:action>
        </xf:model>
    </head>
    <body>
        <h3>Suggest Event Test</h3>
        <xf:input ref="instance('my-form')/element[1]" incremental="true" id="field-1">
            <xf:label>Term 1:</xf:label>
            <xf:action ev:event="DOMFocusIn">             
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'Focus into input 1'"/>
            </xf:action>
            <xf:action ev:event="xforms-value-changed">
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'Value changed in input 1'"/>
                <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[1]"/>
               <xf:send submission="get-suggestions"/>
            </xf:action>
            <xf:action ev:event="DOMFocusOut">
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'Out of input 1'"/>
               <xf:setvalue ref="instance('selected-word')/calling-element" value="'1'"/>
            </xf:action>
        </xf:input>
        <br/>
        <br/>
       
       <xf:input ref="instance('my-form')/element[2]" incremental="true" id="field-2">
            <xf:label>Term 2:</xf:label>
           <xf:action ev:event="DOMFocusIn">             
              <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
              <xf:setvalue ref="instance('log')/event[last()]" value="'FocusIn input 2'"/>
           </xf:action>
            <xf:action ev:event="xforms-value-changed">
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'Value changed in input 2'"/>
               <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[2]"/>
               <xf:send submission="get-suggestions"/>
            </xf:action>
            <xf:action ev:event="DOMFocusOut">
               <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
               <xf:setvalue ref="instance('log')/event[last()]" value="'FocusOut input 2'"/>
               <xf:setvalue ref="instance('selected-word')/calling-element" value="2"/>
            </xf:action>
        </xf:input>
        <br/>
        <br/>
       
       <xf:input ref="instance('my-form')/element[3]" incremental="true" id="field-3">
            <xf:label>Term 3:</xf:label>
           <xf:action ev:event="DOMFocusIn">             
              <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
              <xf:setvalue ref="instance('log')/event[last()]" value="'FocusIn input 3'"/>
           </xf:action>
            <xf:action ev:event="xforms-value-changed">
                <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                <xf:setvalue ref="instance('log')/event[last()]" value="'Value changed in input 3'"/>
               <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[3]"/>
               <xf:send submission="get-suggestions"/>
            </xf:action>
            <xf:action ev:event="DOMFocusOut">
               <xf:setvalue ref="instance('selected-word')/calling-element" value="'3'"/>
            </xf:action>
       </xf:input>
       
        <xf:group ref="instance('conditional-views')/suggest-view">
            <div id="suggest">
                <span>suggestions:</span>
                <xf:repeat id="results-repeat" nodeset="instance('suggest-results')/ingredient">
                    <xf:trigger>
                        <xf:label>
                            <xf:output ref="."/>
                        </xf:label>
                        <!-- When the use clicks on  suggestion -->
                        <xf:action ev:event="DOMActivate">
                            <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                            <xf:setvalue ref="instance('log')/event[last()]" value="concat('Clicked on a suggestion word:',
                                instance('suggest-results')/word[index('results-repeat')])"/>
                           <xf:setvalue ref="instance('my-form')/element[number(instance('selected-word')/calling-element)]" 
                              value="instance('suggest-results')/ingredient[index('results-repeat')]"/>
                        </xf:action>
                    </xf:trigger>
                </xf:repeat>
            </div>
        </xf:group>
        <br/>
       <xf:output ref="instance('selected-word')/calling-element"><xf:label>Prior-field: </xf:label></xf:output>
       <br/>
        
        <div id="showlog">
            <span>
                <b>Event Log</b>
            </span>
            <xf:repeat id="log-repeat" nodeset="instance('log')/event">
                <xf:output ref="."/>
            </xf:repeat>
        </div>
    </body>
</html>

Discussion[edit]

The above example also has several lines of event logging that can be removed in a production application.

As the user is typing and they see a suggestion they like in the suggestion view they will click on the suggested item trigger. When the focus moves out of the field we must keep track of the element that they just left. This is done by the following:

<xf:action ev:event="DOMFocusOut">
   <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
   <xf:setvalue ref="instance('log')/event[last()]" value="'Out of input 1'"/>
   <xf:setvalue ref="instance('selected-word')/calling-element" value="'1'"/>
</xf:action>

This example attempts to reuse the selection functions for many elements. To do this we have to get the items selected into the right field. In this example we just set an integer value for the element.

Although this works if all your elements have the same element name you will have to replace the last setvalue with an equivalent string expression if you have many complex items in a form that need suggested values.

Setting the Field Value[edit]

The following action is used when the use clicks on suggestion:

<xf:action ev:event="DOMActivate">
   <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
   <xf:setvalue ref="instance('log')/event[last()]" 
       value="concat('Clicked on a suggestion word:', instance('suggest-results')/word[index('results-repeat')])"/>
   <xf:setvalue ref="instance('my-form')/element[number(instance('selected-word')/calling-element)]" 
                              value="instance('suggest-results')/word[index('results-repeat')]"/>
</xf:action>

The first two values are only for logging. The last setvalue sets the field of the element that has the calling-element value. So for the second element the value would be instance('my-form')/element[2].

Sample XQuery[edit]

As an example XQuery, we have a collection of "Term" elements with "TermName" subelements. The following XQuery is use for our server side script. If you use eXist just place it in the same collection as the form and call it "suggest-item.xq"

xquery version "1.0";
declare namespace exist="http://exist.sourceforge.net/NS/exist";
declare option exist:serialize "method=xml media-type=text/xml indent=yes";
let $collection-path := '/db/mdr/glossaries/data'
let $search-str := request:get-parameter('prefix', '')
return
<suggestions>{
       for $term in collection($collection-path)/Term[starts-with(TermName/text(),$search-str)]
       return <item>{$term/TermName/text()}</item>
}</suggestions>

Link to Non-logging XForms Application[edit]

Load Non-logging XForms Application

Version with no logging[edit]

<html xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Suggest Event Test</title>
        <style type="text/css">
           @namespace xf url("http://www.w3.org/2002/xforms");
           body {font-family: Helvetica, sans-serif}
	       #suggest {
            	position: absolute;
            	top: 0;
            	margin: 0 0 0 300px;
            	width: auto;
            	border: 1px solid blue;			
	       }
	   </style>
       <xf:model>
          <xf:instance xmlns="" id="my-form">
              <data>
                  <element/>
                  <element/>
                  <element/>
              </data>
          </xf:instance>
          <xf:instance xmlns="" id="conditional-views">
              <data>
                  <suggest-view/>
              </data>
           </xf:instance>

           <!-- only show the suggested values if we have more than one suggestion -->
           <xf:bind nodeset="instance('conditional-views')/suggest-view" 
                     relevant="count(instance('suggest-results')//ingredient) &gt; 1"/>

        	<!-- this is the place that we store the parameters that are going out to the remote suggest service -->
            <xf:instance id="suggest-query">
                <query xmlns="">
                    <prefix/>
                </query>
            </xf:instance>
           
           <!-- this is where we put an ID to the calling element  -->
            <xf:instance xmlns="" id="selected-word">
                <data>
                    <calling-element/>
                </data>
            </xf:instance>
        	
           <!-- this is where we put the suggested ingredients that are returned from the server -->
           <xf:instance id="suggest-results" xmlns="">
                <suggestions/>
            </xf:instance>
           
            <!-- This sends the request to the ingredient suggestion service at the U of West England.  -->
            <!-- Please make a local copy if you are doing more than a few examples for learning XForms and XQuery -->
            <xf:submission id="get-suggestions" action="http://www.cems.uwe.ac.uk/xmlwiki/XForms/suggest-ingredient.xq" 
                method="get" separator="&amp;" 
                ref="instance('suggest-query')" 
                replace="instance" instance="suggest-results">
            </xf:submission>
 
           <!-- this is where we put the logging events -->
            <xf:instance id="log">
                <data xmlns="">
                    <event/>
                </data>
            </xf:instance>           
           
            <!-- put the cursor in the first field when the form becomes ready -->
            <xf:action ev:event="xforms-ready">
                <xf:setfocus control="field-1"/>
            </xf:action>
        </xf:model>
    </head>
    <body>
       <h3>Suggest Event Test</h3>
       <xf:input ref="instance('my-form')/element[1]" incremental="true" id="field-1">
           <xf:label>Term 1:</xf:label>
           <xf:action ev:event="xforms-value-changed">
              <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[1]"/>
              <xf:send submission="get-suggestions"/>
           </xf:action>
           <xf:action ev:event="DOMFocusOut">
              <xf:setvalue ref="instance('selected-word')/calling-element" value="'1'"/>
           </xf:action>
       </xf:input>
       <br/>
       <br/>
       
       <xf:input ref="instance('my-form')/element[2]" incremental="true" id="field-2">
          <xf:label>Term 2:</xf:label>
          <xf:action ev:event="xforms-value-changed">
             <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[2]"/>
             <xf:send submission="get-suggestions"/>
          </xf:action>
          <xf:action ev:event="DOMFocusOut">
             <xf:setvalue ref="instance('selected-word')/calling-element" value="2"/>
          </xf:action>
       </xf:input>
       <br/>
       <br/>
       
       <xf:input ref="instance('my-form')/element[3]" incremental="true" id="field-3">
            <xf:label>Term 3:</xf:label>
            <xf:action ev:event="xforms-value-changed">
               <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[3]"/>
               <xf:send submission="get-suggestions"/>
            </xf:action>
            <xf:action ev:event="DOMFocusOut">
               <xf:setvalue ref="instance('selected-word')/calling-element" value="'3'"/>
            </xf:action>
       </xf:input>
       
        <xf:group ref="instance('conditional-views')/suggest-view">
            <div id="suggest">
               <span>suggestions:</span>
               <xf:repeat id="results-repeat" nodeset="instance('suggest-results')/ingredient">
                   <xf:trigger>
                       <xf:label>
                           <xf:output ref="."/>
                       </xf:label>
                       <!-- When the use clicks on  suggestion -->
                       <xf:action ev:event="DOMActivate">
                           <xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
                           <xf:setvalue ref="instance('log')/event[last()]" value="concat('Clicked on a suggestion word:', instance('suggest-results')/word[index('results-repeat')])"/>
                           <xf:setvalue ref="instance('my-form')/element[number(instance('selected-word')/calling-element)]" 
                              value="instance('suggest-results')/ingredient[index('results-repeat')]"/>
                       </xf:action>
                   </xf:trigger>
                </xf:repeat>
            </div>
        </xf:group>
    </body>
</html>

Using Minimal Trigger Appearance[edit]

If you do not like the appearance of the button in the trigger you can add the appearance="minimal" attribute to the trigger element.

The following CSS will reverse the background and font colors when the user hovers over the trigger:

.suggestion:hover {
   background-color: blue;
   color: white;
   padding: 3px;
   font-size: 10pt;
}

Preventing Null Searches[edit]

XForms 1.1 added the conditional event attribute. You can use this to only request an suggestion from the server if the element is at least one character long.

<xf:action ev:event="xforms-value-changed" if="string-length(instance('save-data')/element[1]) gt 0">
      <xf:setvalue ref="instance('suggest-query')/prefix" value="instance('save-data')/element[1]"/>
      <xf:send submission="get-suggestions"/>
</xf:action>

Discussion[edit]

The functionality of suggesting items is contained in the Orbeon Autocomplete component Orbon XBL Autocomplete

XSLTForms has an example that uses the JSON results from Wikipedia search to suggest pages: XSLT Autocomplete example

Next Page: Slideshow | Previous Page: Dynamic Labels

Home: XForms



Dynamic Selection Lists

Motivation[edit]

You want that the content of a selection list to depend on the value another selection list. This is also known as "Cascading Selection".

Method[edit]

We have two instances in a model. The first instance populates the first select1 list. The second select1 uses an xf:itemset to only select the relevant items from the second instance. In effect we are adding a "where" clause to the list of items selected in the second list.

The presented form shows an example where the user can select a season (Spring, Summer,...) and in a second select the user will only be able to select from the relevant month in that season.

We also will automatically set the month to null when the season selection changes to make sure our pairing is always valid.

The example had been tested with Firefox 2.0.0.12 and the Mozilla XForms add on 0.8.4 as well as on FireFox 3.0.

Screen Image[edit]

Cascading Selects

Link to XForms Application[edit]

Load Example XForms Application

Note that the initial values of the selections are set in the instance values.

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xf="http://www.w3.org/2002/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Test conditional selection lists</title>
      <xf:model>

         <xf:instance id="selected-values" xmlns="">
            <data>
               <selected-season>Winter</selected-season>
               <selected-month>January</selected-month>
            </data>
         </xf:instance>

         <xf:instance id="seasons" xmlns="">
            <root>
               <item name="Spring"/>
               <item name="Summer"/>
               <item name="Autumn"/>
               <item name="Winter"/>
            </root>
         </xf:instance>

         <xf:instance id="months" xmlns="">
            <root>
               <item name="January" season="Winter"/>
               <item name="February" season="Winter"/>
               <item name="March" season="Spring"/>
               <item name="April" season="Spring"/>
               <item name="May" season="Spring"/>
               <item name="June" season="Summer"/>
               <item name="July" season="Summer"/>
               <item name="August" season="Summer"/>
               <item name="September" season="Autumn"/>
               <item name="October" season="Autumn"/>
               <item name="November" season="Autumn"/>
               <item name="December" season="Winter"/>
            </root>
         </xf:instance>
         <xf:bind id="selected-season" nodeset="instance('selected-values')/selected-season"/>
      </xf:model>
   </head>
   <body>
      <p>Test conditional selection lists -
         month selector depends on the current season</p>

         <xf:select1 ref="instance('selected-values')/selected-season">
           <xf:label>Season:</xf:label>
           <xf:itemset nodeset="instance('seasons')/item">
             <xf:label ref="@name"/>
             <xf:value ref="@name"/>
           </xf:itemset>
           <!-- As soon as you chance this value we set the month to be blank -->
           <xf:action ev:event="xforms-value-changed">
              <xf:setvalue ref="instance('selected-values')/selected-month" value="''"/>
           </xf:action>
         </xf:select1>
         <br/>
         <xf:select1 ref="instance('selected-values')/selected-month">
           <xf:label>Month:</xf:label>
           <xf:itemset nodeset="instance('months')/item[@season=instance('selected-values')/selected-season]">
             <xf:label ref="@name"/>
             <xf:value ref="@name"/>
           </xf:itemset>
         </xf:select1>
         <br/>
         <xf:output ref="instance('selected-values')/selected-season">
            <xf:label>selected-season: </xf:label>
         </xf:output>
		  <br/>

         <xf:output ref="instance('selected-values')/selected-month">
            <xf:label>selected-month: </xf:label>
         </xf:output>

         <h4>Relevant Months using Repeat</h4>
	   <xf:repeat nodeset="instance('months')/item[@season=instance('selected-values')/selected-season]">
		   <xf:output ref="@name"/>
	   </xf:repeat>

   </body>
</html>

Updating the Second Select When the First Select Changes[edit]

Note that we have added an action and trap the xforms-value-changed event to the first select1 statement. We use the xf:setvalue event to change the value of the second select1 to be blank. This will guarantee that the pair of values will always be consistent.

<xf:select1>
.....
     <!-- As soon as you chance this value we set the month to be null -->
     <xf:action ev:event="xforms-value-changed">
          <xf:setvalue ref="instance('selected-values')/selected-month" value="''"/>
     </xf:action>
</xf:select1>

This suggestion was made by Aaron Reed.


Next Page: Deep Copy with Insert Origin | Previous Page: Referencing Items

Home: XForms



Incremental Model Loading

Motivation[edit]

You have a large model and you want to incrementally load different portions of the model when they are needed. This is frequently done when you have a multi-part form and each tab needs additional data. Loading only the data for the initial tab keeps your form load times fast and avoids unnecessarily locking shared data resources.

Method[edit]

We will create a model with three separate instances, one for a list of people, one for a list of places and one for a list of things. The people will automatically be loaded into the form when the form loads. We will create triggers that will incrementally load the other portions of the model when they are needed. Each trigger will use a submission event that does a separate HTTP get to incrementally load data into a separate instance in the model.

Here is the empty place-holder instance in the model for the places and the submission to get the places data.

<xf:instance id="places">
    <null/>
</xf:instance>
<xf:submission id="get-places" method="get" action="places.xml"
    replace="instance" instance="places"/>

Here is the trigger (button) that gets the new model.

<xf:submit submission="get-places">
    <xf:label>Load Places</xf:label>
</xf:submit>

Screen Image[edit]

The following are the before and after screen images. The before screen image is when the form initially loads. The after image is after the user has pressed the two triggers for loading the places and things.

Before Model Fully Loaded
After Model Fully Loaded

The above example is designed to be very easy to see how data is loaded when an event is triggered. In practice each tab in a multi-tab form may have some data that is only needed if the users click on that tab. This is a perfect use of dynamic model loading. The example below illustrates this best-practice.

Note event log does not reload model data

Load XForms Application[edit]

Example with triggers that manually load incremental data: Load XForms Application

Example with tab-selection events that incrementally load data Load XForms Application

Note that in this example the event log shows that the data is only loaded once regardless of how many times the tab is selected.

Avoiding Reloads[edit]

The following is an example of how to use conditional actions to check if a instance in the model already has its data loaded into the form:

<xf:case id="places-case">
     <xf:action ev:event="xforms-select" if="not(instance('places')/place)">
         <xf:send submission="get-places"/>
     </xf:action>
     <h2>Places</h2>
</xf:case>

The if attribute of the xf:action checks to see if there is at least one place in the places instance. If there is not at least one "place" the submission event is fired.

Sample Code[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
  <head>
    <title>Incremental Model Loading</title>
    <style type="text/css">body {font-family: Helvetica, Arial, sans-serif;</style>
    <xf:model>
      <!-- unconditionally loaded when the form loads -->
      <xf:instance id="people" src="people.xml">
          <null/>
      </xf:instance>
      
       <xf:instance id="places">
        <null/>
      </xf:instance>
      <xf:submission id="get-places" method="get" action="places.xml"
        replace="instance" instance="places"/>
      
       <xf:instance id="things">
        <null/>
      </xf:instance>
      <xf:submission id="get-things" method="get" action="things.xml"
        instance="things" replace="instance"/>
        
    </xf:model>
  </head>

  <body>        
    <h1>Incremental Model Loading</h1>
    <p>Not all parts of the model need to be loaded into a form when it is first loaded.  For
    large models, different sections can be loaded as they are needed.</p>

    <h2>People</h2>
      <xf:group ref="instance('people')">
         <xf:repeat nodeset="person">
           <xf:output ref="name"/><br/>
        </xf:repeat>
      </xf:group>
      
      <h2>Places</h2>
      <xf:group ref="instance('places')">
         <xf:repeat nodeset="place">
            <xf:output ref="name"/><br/>
        </xf:repeat>
        <xf:submit submission="get-places">
            <xf:label>Load Places</xf:label>
          </xf:submit>
      </xf:group>
      
      <h2>Things</h2>
      <xf:group ref="instance('things')">
         <xf:repeat nodeset="item">
            <xf:output ref="name"/><br/>
         </xf:repeat>
         <xf:submit submission="get-things">
            <xf:label>Load Things</xf:label>
          </xf:submit>
     </xf:group>

  </body>
</html>

XML Instance Samples[edit]

[people.xml] [places.xml] [things.xml]



Dynamic Labels in Local language

Motivation[edit]

Sometimes you may want to change the label dynamically from one language to another language without loading the form. In the given example, you can choose the language from the select1 control option.

Screen Image[edit]

Local lang english.pngLocal lang hindi.pngLocal lang tamil.png

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
	<title>e-District - Regd Form</title>
	<!--<link href="edistrict.css" rel="stylesheet"/>-->
	  <style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
 BODY 
 { 
   font-family: Times New Roman,Times,serif;
   font-size: 12pt;
   font-style: normal;
   font-weight:normal;
   font-variant: normal;
   text-align: left;
   word-spacing: normal;
   letter-spacing: normal;
   /*background-color: transparent;*/
   background-image: url(Desktop/tour_xforms/NIC_Logo.gif); background-repeat: no-repeat;
   background-position: right top;
   line-height:20pt;
 }	
 
 
   xf|input, xf|secret {
      display: table-row;
   }
 
   xf|value {
      text-align: left;
   }
 
div.content div.tab-box {
   position: absolute;
   width: 120px;
}
 
div{line-height:20pt;}
h3 {text-align: center;}
h4 {color:maroon;text-decoration:underline;}

div.formbody
     {
	margin-left:2in;
	margin-right:0.5in; 
	width:8.5in;	
     }

xf|input {display: table-row;text-align:left;}
xf|input > xf|label {display: table-cell;  width:160pt; font-weight:bold;text-align:left;}
xf|input .xf-value  {width: 100pt;font-size:10pt;}

xf|secret { display: table-row;text-align:left;}
xf|secret > xf|label { display: table-cell;  width:160pt; font-weight:bold;text-align:left;}
xf|secret .xf-value {width: 100pt;font-size:10pt;}

xf|output { display: table-row;text-align:left;}
xf|output > xf|label { display: table-cell;  width:160pt; font-weight:bold;text-align:left;}
xf|output .xf-value  {width: 100pt;font-size:11pt;font-weight:bold;color:blue;text-align:left;}

xf|select1 { display: table-row;text-align:left;}
xf|select1 > xf|label { display: table-cell;  width:160pt; font-weight:bold;text-align:left;}
xf|select1 .xf-value {max-width: 100pt;font-size:10pt;}
	</style>
	<xf:model id="model1">
		
		<xf:instance id="Regd_Form" xmlns="">
			<form CAN="" xmlns="">
				<name></name>
				<DOB></DOB>
				<address></address>
				<loginId></loginId>
				<mobile></mobile>
				<phone></phone>
				<email></email>
				<password></password>
				<repeat_pass></repeat_pass>
				
			</form>
		</xf:instance>
		<xf:instance id="slanguage1" xmlns="">
			<language xmlns="">
				<lang>English</lang>
				<lang_list><item>English</item></lang_list>
				<lang_list><item>தமிழ்</item></lang_list>
				<lang_list><item>हिन्दी</item></lang_list>
			</language>
		</xf:instance>
		<xf:instance id="slanguage" xmlns="">
		<language xmlns="">
			<lang name="English" rname="Registration Form" smessage="Registration Completed Successfully" 
			emessage="Error Occurred .. Pls Check the Entered Details" sbutton="Save" cbutton="Reset" e1msg="Wrong Password!Please Re-enter">
				<name>Applicant Name</name>
				<DOB>Date of Birth</DOB>
				<address>Address</address>
				<loginId>Desired Login ID</loginId>
				<mobile>Mobile No</mobile>
				<phone>Phone No</phone>
				<email>E-mail ID</email>
				<password>Password</password>
				<repeat_pass>Re-Enter Password</repeat_pass>
			</lang>
			<lang name="தமிழ்" rname="பதிவு படிவம்" smessage="பதிவு சேமிக்கப்பட்டது" 
			emessage="தவறு! விபரங்களை சரிப்பார்க்கவும்" sbutton="சேமி" cbutton="மீளமை" e1msg="கடவுச்சொல் தவறு!மீண்டும் உறுதிப்படுத்துக">
				<name>விண்ணப்பதாரர் பெயர்</name>
				<DOB>பிறந்த தேதி</DOB>
				<address>முகவரி</address>
				<loginId>விருப்பப்படும் நுழைவு பெயர்</loginId>
				<mobile>கைத் தொலைபேசி எண் </mobile>
				<phone>தொலைபேசி எண்</phone>
				<email>மின்னஞ்சல் முகவரி</email>
				<password>கடவுச்சொல்</password>
				<repeat_pass>கடவுச்சொல் உறுதிப் படுத்து</repeat_pass>
			</lang>
			<lang name="हिन्दी" rname="पंजीकरण फार्म" smessage="पंजीकरण सफलतापूर्वक पूरा" 
			emessage="त्रुटि हुई .. Pls दर्ज विवरण की जाँच करें" sbutton="Save" cbutton="Reset" e1msg="पासवर्ड गलत! फिर से दर्ज करें">
				<name>आवेदक का नाम</name>
				<DOB>जन्म तिथि</DOB>
				<address>पता</address>
				<loginId>वांछित लॉगिन आईडी</loginId>
				<mobile>मोबाइल नंo</mobile>
				<phone>फोन नंo</phone>
				<email>ई - मेल आईडी</email>
				<password>पासवर्ड</password>
				<repeat_pass>पुनः पासवर्ड दर्ज करिए</repeat_pass>
			</lang>			
		</language>
		</xf:instance>
		
		<xf:action ev:event="xforms-ready">
 			<xf:setvalue ref="DOB" value="substring(now(),1,10)"/>
		</xf:action>
		<xf:bind nodeset="instance('Regd_Form')/DOB" type="xs:date" required="true()"/>
		

		<xf:submission id="submit" method="put" action="result.xml">
			<xf:action ev:event="xforms-submit-done">
		
			<xf:message level="modal"><xf:output ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@smessage"></xf:output> ...</xf:message>
			</xf:action>
			<xf:message level="modal" ev:event="xforms-submit-error"><xf:output ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@emessage"></xf:output></xf:message>
		</xf:submission>
	</xf:model>
</head>
<body bgcolor="#ACBCD8">

	<div id="img">
		<img src="img.png" width="1027" />
	</div><br/>
	<div id="formbody"  style="width:10.7in;">
 <div class="content">
 
     
      </div> 
	<center>
	<xf:select1 ref="instance('slanguage1')/lang">
		<xf:label>Select Language</xf:label>
		<xf:itemset nodeset="instance('slanguage1')/lang_list">
			<xf:label ref="item"/>
			<xf:value ref="item"/>
		</xf:itemset>
	</xf:select1><br/>
 <fieldset style="width: 700px;border:solid 1pt black" >
         
	<h3><xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@rname"></xf:label></h3><br/>
		<xf:input ref="instance('Regd_Form')/name">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/name">:</xf:label>
		</xf:input>
		<xf:input ref="instance('Regd_Form')/DOB">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/DOB">:</xf:label>
		</xf:input>
		<xf:input ref="instance('Regd_Form')/address">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/address"> :</xf:label>
		</xf:input>
		<xf:input ref="instance('Regd_Form')/loginId">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/loginId"> :</xf:label>
		</xf:input>
		<xf:input ref="instance('Regd_Form')/mobile">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/mobile">:</xf:label>
		</xf:input>
		<xf:input ref="instance('Regd_Form')/phone">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/phone"> :</xf:label>
		</xf:input>
		<xf:input ref="instance('Regd_Form')/email">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/email"> :</xf:label>
		</xf:input>
		<xf:secret ref="instance('Regd_Form')/password">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/password"> :</xf:label>
			<!--<xf:alert level="modal">கடவுச்சொல் 3 முதல் 7 எழுத்து மட்டுமே</xf:alert>-->
		</xf:secret>
		<xf:secret ref="instance('Regd_Form')/repeat_pass">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/repeat_pass"> :</xf:label>
			<xf:action ev:event="DOMFocusOut" if="instance('Regd_Form')/repeat_pass != instance('Regd_Form')/password">
				<xf:setvalue ref="instance('Regd_Form')/repeat_pass" value="''"/>
				<xf:message level="modal">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@e1msg"></xf:label></xf:message>
				
			</xf:action>
		</xf:secret><br/>
		<xf:submit submission="submit">
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@sbutton"></xf:label>
			
			
		</xf:submit>
		<xf:trigger>
			<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@cbutton"></xf:label>
			<xf:reset ev:event="DOMActivate" target="model1"/>
		</xf:trigger>
 </fieldset>
	</center><br/>



</div>
</body>
</html>

Credits[edit]

This example was originally inspired by Kurt Cagle.



Search Form

Motivation[edit]

You want to create a search form that uses a single input text field and submits a search request to a search service on a remote web server.

Discussion[edit]

We are all familiar with the simple front end to search engines like Google that display a simple search field. There are two simple features we will demonstrate in the first version. 1) The input cursor will be positioned in the search field when the form loads. When you press the "Enter" key the search will automatically be executed.

We will also discuss a way to have a single form display both simple search and complex search functions.

Method[edit]

We will first create a simple search input field and give it an id of "search-field". We will also add an action to the input that will fire off the submission when the Enter key is pressed.

<xf:input ref="q" id="search-field">
   <xf:label>Search string:</xf:label>
   <xf:action ev:event="DOMActivate">
      <xf:send submission="search"/>
   </xf:action>
</xf:input>

In this example, q is a reference to the query string we will be sending to the remote server.

From the prior example we learned that you can have the cursor automatically positioned in the search field when the form loads by adding the following action added to your model:

<xf:model>
  ...
  <xf:action ev:event="xforms-ready">
      <xf:setfocus control="search-field"/>
  </xf:action>
...
</xf:model>

Screen Image[edit]

Sample Google Search Form

Link to XForms Application[edit]

Load XForms Application

Sample Program[edit]

In this example we will create a simple front end to Google's search engine. The format of the REST API for the Google search engine is the following:

http://www.google.com/search?hl=en&q=XForms

In this REST query the parameters are:

  • hl = language (en for English)
  • q = search query string

We can create an instance that has these parameters in our model:

<xf:instance xmlns="">
   <data>
      <hl>en</hl>
      <q></q>
   </data>
</xf:instance>

Full Program Listing[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:ev="http://www.w3.org/2001/xml-events" >
    <head>
        <title>Google Search Example</title>
        <style type="text/css">  
         body {font-family: Helvetica, sans-serif}        
        </style>
        <xf:model>
            <xf:instance xmlns="" id ="search-params">
                <data>
                    <hl>en</hl>
                    <q></q>
                </data>
            </xf:instance>
        <!-- Send the search parameters to the Google search engine and replace this entire form with the results -->
            <xf:submission id="search-google" method="get" 
            action="http://www.google.com/search" replace="all"
            separator="&amp;"/>

        <!-- put the cursor in the first field when the form becomes ready -->
            <xf:action ev:event="xforms-ready">
                <xf:setfocus control="search-field"/>
            </xf:action>
        </xf:model>
    </head>
    <body>
        <h1>Google Search Example</h1>
        <xf:input ref="instance('search-params')/q" id="search-field">
            <xf:label>Search string:</xf:label>
            <xf:action ev:event="DOMActivate">
                <xf:send submission="search-google"/>
            </xf:action>
        </xf:input>
        <xf:submit submission="search-google">
            <xf:label>Search</xf:label>
        </xf:submit>
    </body>
</html>

Discussion[edit]

You can also send over a dozen other parameters to the Google search service. For example if you want to restrict the search results to a specific web site or sub-site you can just add an additional "site" parameter that restricts search results to that site. For example the following URL will restrict the search results to pages on this wikibook:

http://www.google.com/search?hl=en&q=xforms+site%3Ahttp%3A%2F%2Fen.wikibooks.org%2Fwiki%2FXForms

Note that because forward slashes are part of the search query they are replaced with a %2F string.

The OpenSearch XML standard may also be of interest. This standard allows any search service to specify the parameters to a search engine and how the data is returned to a search client.


Next Page: Annotations | Previous Page: Setting Initial Cursor

Home: XForms



Search with Load

Motivation[edit]

You want to build a web form that does a search using the xf:load element. This allows you to rewrite the URL to the search application.

Source Code[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms" 
    xmlns:ev="http://www.w3.org/2001/xml-events" >
    <title>Example of XForms Search with xf:load</title>
    <style type="text/css">  
        body {font-family: Helvetica, sans-serif}    
    </style>
    <xf:model>
        <xf:instance xmlns="" id="search-params">
            <data>
                <url>http://www.example.com/search?q=</url>
                <q></q>
            </data>
        </xf:instance>
        
        <!-- put the cursor in the first field when the form becomes ready -->
        <xf:action ev:event="xforms-ready">
            <xf:setfocus control="search-field"/>
        </xf:action>
        
    </xf:model>
    <body>
        <h1>Example of XForms Search with xf:load</h1>
        <xf:input ref="q" id="search-field" incremental="true">
            <xf:label>Enter search string:</xf:label>
            <xf:action ev:event="DOMActivate">
                <xf:load show="replace">
                    <xf:resource value="concat(url, q)"/>
                </xf:load>
            </xf:action>
        </xf:input>
        
        <xf:trigger>
            <xf:label>Execute Search</xf:label>
            <xf:action ev:event="DOMActivate">
                <xf:load show="replace">
                    <xf:resource value="concat(url, q)"/>
                </xf:load>
            </xf:action>
        </xf:trigger>
        
    </body>
</html>

Discussion[edit]

Note that you must use the xf:value attribute of the resource element.



Advanced Search

Motivation[edit]

You want a simple search function and a separate advanced search options tab.

Source Code[edit]

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ev="http://www.w3.org/2001/xml-events">
    <title>Google Search Example</title>
    <style type="text/css">  
         body {font-family: Helvetica, sans-serif; }        
    </style>
    <style>
        @namespace xf url("http://www.w3.org/2002/xforms");
        /* all the attributes of each tab, except the background color */
        #horiz-tab-menu xf|trigger {
        border-left: black solid 1px;
        border-top: black solid 1px;
        border-right: black solid 1px;
        border-bottom: 0px;
        font-weight: bold;
        font-family: Helvetica, sans-serif;
        font-size: .9em;
        margin-right: 5px;
        padding: 3px;
        /* the following only works under FireFox */
        -moz-border-radius: .5em .5em 0em 0em;
        border-radius-topright: .5em;
        border-radius-topleft: .5em;
        }
        /* the attributes of each div inside of a case */
        xf|switch xf|case {
        position: relative;
        width: 400;
        border: solid black 1px;
        border-top: solid black 0px;
        border-right: solid black 1px;
        border-bottom: solid black 1px;
        padding: 5px;
        background-color: silver;
        }

    </style>
    <xf:model>
        <xf:instance xmlns="" id="search-params">
            <data>
                <hl>en</hl>
                <q />
            </data>
        </xf:instance>

        <xf:instance xmlns="" id="adv-search-input-params">
            <data>
                <hl>en</hl>
                <q>Xforms</q>
                <site>http://en.wikibooks.org/wiki/XForms</site>
            </data>
        </xf:instance>

        <xf:instance xmlns="" id="adv-output-input-params">
            <data>
                <hl>en</hl>
                <q />
            </data>
        </xf:instance>

        <xf:bind nodeset="instance('adv-output-input-params')/q"
            calculate="concat(
            instance('adv-search-input-params')/q, '+',  instance('adv-search-input-params')/site)" />
 
        <xf:bind nodeset="instance('adv-output-input-params')/hl"
            calculate="instance('adv-search-input-params')/hl"/>
        
        <!-- Send the search parameters to the Google search engine and replace this entire form with the results -->
        <xf:submission id="search-google" method="get" action="http://www.google.com/search"
            replace="all" ref="instance('search-params')" separator="&amp;" />

        <xf:submission id="adv-search-google" method="get" action="http://www.google.com/search"
            replace="all" ref="instance('adv-output-input-params')" separator="&amp;" />

        <!-- put the cursor in the first field when the form becomes ready -->
        <xf:action ev:event="xforms-ready">
            <xf:setfocus control="search-field" />
        </xf:action>
    </xf:model>
    <body>
        <h1>Google Search Example</h1>
        <div id="horiz-tab-menu">
            <xf:trigger appearance="minimal" class="tab">
                <xf:label>Simple</xf:label>
                <xf:toggle case="simple-search" ev:event="DOMActivate" />
            </xf:trigger>
            <xf:trigger appearance="minimal" class="tab">
                <xf:label>Complex</xf:label>
                <xf:toggle case="advanced-search" ev:event="DOMActivate" />
            </xf:trigger>
        </div>
        <xf:switch>

            <xf:case id="simple-search">
                <xf:input ref="instance('search-params')/q" id="search-field">
                    <xf:label>Search string:</xf:label>
                    <xf:action ev:event="DOMActivate">
                        <xf:send submission="search-google" />
                    </xf:action>
                </xf:input>
                <xf:submit submission="search-google">
                    <xf:label>Search</xf:label>
                </xf:submit>
            </xf:case>

            <xf:case id="advanced-search">
                <xf:input ref="instance('adv-search-input-params')/q" id="adv-search-field">
                    <xf:label>Search string:</xf:label>
                    <xf:action ev:event="DOMActivate">
                        <xf:send submission="adv-search-google" />
                    </xf:action>
                </xf:input>
                <br />
                <xf:input ref="instance('adv-search-input-params')/site" id="site-field">
                    <xf:label>Site URL:</xf:label>
                    <xf:action ev:event="DOMActivate">
                        <xf:send submission="adv-search-google" />
                    </xf:action>
                </xf:input>
                <br />
                <xf:submit submission="adv-search-google">
                    <xf:label>Search</xf:label>
                </xf:submit>
            </xf:case>

        </xf:switch>
    </body>
</html>

Discussion[edit]

Next Page: Pie Chart | Previous Page: Dynamically Load JavaScript

Home: XForms



Date Range Search

Motivation[edit]

You want to limit search results based on one or more dates within items.

Method[edit]

We will create a XForms application that will have two calendar selectors. We can use the built-in calendar selector or allow users to select the year, month, day values separately.

Month Code Table[edit]

<code-table>
    <code-table-name>date-month-code</code-table-name>
    <description>A list of all the month codes for doing searchs.</description>
    <items>
        <item>
            <label>January</label>
            <numeric-id>1</numeric-id>
            <abbreviation>Jan</abbreviation>
            <value>january</value>
        </item>
        <item>
            <label>February</label>
            <numeric-id>2</numeric-id>
            <abbreviation>Feb</abbreviation>
            <value>february</value>
        </item>
        <item>
            <label>March</label>
            <numeric-id>3</numeric-id>
            <abbreviation>Mar</abbreviation>
            <value>march</value>
        </item>
        <item>
            <label>April</label>
            <numeric-id>4</numeric-id>
            <abbreviation>Apr</abbreviation>
            <value>april</value>
        </item>
        <item>
            <label>May</label>
            <numeric-id>5</numeric-id>
            <abbreviation>May</abbreviation>
            <value>may</value>
        </item>
        <item>
            <label>June</label>
            <numeric-id>6</numeric-id>
            <abbreviation>Jun</abbreviation>
            <value>june</value>
        </item>
        <item>
            <label>July</label>
            <numeric-id>7</numeric-id>
            <abbreviation>Jul</abbreviation>
            <value>july</value>
        </item>
        <item>
            <label>August</label>
            <numeric-id>8</numeric-id>
            <abbreviation>Aug</abbreviation>
            <value>august</value>
        </item>
        <item>
            <label>September</label>
            <numeric-id>9</numeric-id>
            <abbreviation>Sep</abbreviation>
            <value>september</value>
        </item>
        <item>
            <label>October</label>
            <numeric-id>10</numeric-id>
            <abbreviation>Oct</abbreviation>
            <value>october</value>
        </item>
        <item>
            <label>November</label>
            <numeric-id>11</numeric-id>
            <abbreviation>Nov</abbreviation>
            <value>november</value>
        </item>
        <item>
            <label>December</label>
            <numeric-id>12</numeric-id>
            <abbreviation>Dec</abbreviation>
            <value>december</value>
        </item>
    </items>
</code-table>



Search flickr

Motivation[edit]

Many sites give you a simple way of using a URL to perform a search. REST (Representational State Transfer) is a structured way to access data on the web without having to use a web service. This example program uses an XForm submission using the Flickr REST service.

Warnings[edit]

This example does NOT work when you load the form locally from a file system. It must run from a webserver.


To run this application you MUST enable XForms to submit data to other domains. In FireFox this is done by adding the domains to your trusted list. This can be done by going to the FireFox "Tools" menu, selecting Preferences, selecting the "Content" tab, and adding the sites to your XForms white listed sites. In this case the trusted domain is "flickr.com"

Screen Image[edit]

File:XForms-flickr.jpg
Search results from flickr using tag "XForms"

Link to XForms Application[edit]

Load Form

Sample Program[edit]

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
  <head>
    <title>Search Flickr using Firefox Form</title>
    <!-- Inspired by http://skimstone.x-port.net/index.php?q=node/89 -->
    <!-- and http://www.mozilla.org/projects/xforms/samples/flickr-search.xhtml -->
    <xf:model>
      <!-- The data sent to flickr -->
      <xf:instance xmlns="">
        <instanceData>
          <method>flickr.photos.search</method>
          <api_key>68149024a667e0be3c63708f002ffe1e</api_key>
          <tags />
          <per_page>12</per_page>
        </instanceData>
      </xf:instance>

      <!-- The data returned by flickr -->
      <xf:instance id="inst-rs" xmlns="">
         <dummy />
      </xf:instance>
      <xf:submission id="sub-flickr"
		     method="get" action="http://www.flickr.com/services/rest/"
		     separator="&amp;"
		     replace="instance" instance="inst-rs">
         <xf:toggle case="case-busy" ev:event="xforms-submit" />
         <xf:toggle case="case-submit-error" ev:event="xforms-submit-error" />
         <xf:toggle case="case-done" ev:event="xforms-submit-done" />
      </xf:submission>

      <!-- Used to hold image size -->
      <xf:instance id="inst-control" xmlns="">
         <instanceData>
           <size>s</size>
         </instanceData>
      </xf:instance>
    </xf:model>

    <!--Mozilla XForms Custom Control-->
    <bindings id="xformsBindings"
	      xmlns="http://www.mozilla.org/xbl"
	      xmlns:html="http://www.w3.org/1999/xhtml">
      <binding id="output-image"
	       extends="chrome://xforms/content/xforms.xml#xformswidget-base">
         <content>
           <html:div>
             <html:img anonid="content" style="float: left; margin-right: 5px;"/>
           </html:div>
         </content>
         <implementation implements="nsIXFormsUIWidget">
            <method name="refresh">
                <body>
                  var img = document.getAnonymousElementByAttribute(this, "anonid", "content");
                  img.setAttribute("src", this.stringValue);
                  return true;
                </body>
           </method>
         </implementation>
      </binding>
    </bindings>

    <!-- Bind the custom control to output with class="image" -->
    <style type="text/css">
      @namespace xf url(http://www.w3.org/2002/xforms);

      xf|output.image {
        -moz-binding: url('#output-image');
      }
    </style>
  </head>

  <!-- BODY -->
  <body>
   <xf:group id="main-body">
     <xf:input ref="tags">

       <xf:label>Search for a tag (f.x. "suzuki"):</xf:label>
     </xf:input>
     <xf:submit submission="sub-flickr">
       <xf:label>Find</xf:label>
     </xf:submit>
     <xf:select1 ref="instance('inst-control')/size" incremental="true">
       <xf:label>Size: </xf:label>
       <xf:item>
          <xf:label>Small</xf:label>
          <xf:value>s</xf:value>
       </xf:item>
       <xf:item>
          <xf:label>Medium</xf:label>
          <xf:value>m</xf:value>
       </xf:item>
     </xf:select1>
     <xf:switch>
         <xf:case id="case-start"></xf:case>
         <xf:case id="case-busy">
            <p>Searching...</p>
         </xf:case>
         <xf:case id="case-submit-error">
            <p>Submission error! Did you remember to allow XForms to submit data to other domains?</p>
         </xf:case>
         <xf:case id="case-done">Done</xf:case>
      </xf:switch>
    <xf:group ref="instance('inst-rs')">
      <xf:output ref="err/@msg"/>
      <xf:repeat nodeset="photos/photo">
         <xf:output
         value="concat(
            'http://static.flickr.com/',
            @server, '/',
            @id, '_',
            @secret, '_',
             instance('inst-control')/size,
             '.jpg'
         )"
         class="image"
        />
     </xf:repeat>
     <div style="clear: both;"></div>
    </xf:group>
   </xf:group>
 </body>
</html>

Discussion[edit]

This example shows how to display a different status message based on the state of a submission using the switch/case/toggle elements.

More to Explore[edit]

The wikipedia page on REST has a list of public implementations of the REST standards. These should be acessible by most XForms (with the appropriate permissions).

REST API from Amazon S3 [2]

References[edit]

This example was taken from the FireFox extension examples page [3] which in turn was taken from the formsPlayer web site [4] where it is part of the Introduction to XForms tutorial [5].


Next Page: Web service | Previous Page: CSS tables

Home: XForms



Web service

Web services can be called directly from an XForms application using the submission element in the model.

Connecting a web service to an Event[edit]

To call a web service you first need to "wire it" up to an event. For example this can be a "submit" button at the end of a form.

The submit element is usually in the presentation (inside the body tag) and is wired to a <submission> element in the model.

<head>
  <xf:model id="my-model">
     <xf:submission id="callWebService">
           <...>
     </xf:submission>
  </xf:model>
</head>
<body>
  <xf:submit submission="callWebService">
     <xf:label>Press Button to Call a Web Service</xf:label>
  </xf:submit>
</body>

Sample Program[edit]

The program consists of several parts.

In the model:

  1. The SOAP submission instance
  2. The submission
  3. The SOAP response placeholder

SOAP input message[edit]

Here is an example of the input SOAP message

 <!-- What we send to the web service -->
 <xf:instance id="submit-instance" xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <soap-env:Envelope>
      <soap-env:Body>
          <m:test xmlns:m="http://www.example.com/web-services/my-operation"
            SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
              <string xsi:type="xsd:string">Hello world!</string>
          </m:test>
       </soap-env:Body>
    </soap-env:Envelope>
 </xf:instance>
 <!-- /env:Envelope/env:Body/m:ecrvTestResponse/result -->

Putting the SOAP Results in an Instance[edit]

When the web service returns you need to put the returning SOAP response in an instance. We create another instance in the model and we also need to give it an identifier. In this case I called it "results-instance".

<xf:instance id="results-instance" xmlns="">
   <env:Envelope/> 
</xf:instance>
<xf:bind id="results-bind" nodeset="instance('results-instance')/env:Envelope"/>

This is just a temporary storage area that the results will be inserted into.

The XForms submission Statement[edit]

<xf:submission id="send-to-dor-document-web-service"
   action="http://www.example.com/web-service/my-web-service" 
   method="post" 
   mediatype="text/xml"
   ref="instance('submit-instance')"
   replace="instance" 
   instance="results-instance">
   <xf:toggle case="case-busy" ev:event="xforms-submit" />
   <xf:toggle case="case-submit-error" ev:event="xforms-submit-error" />
   <xf:toggle case="case-done" ev:event="xforms-submit-done" />         
</xf:submission>

There are few things to note. The action attribute is the URL of the connection point of the web service. The operation you call is not included in the URL.

The method (get, put or post) in this case is a post.

Mediatype[edit]

XForms is a rich application development standard. So by default the HTTP transactions used by XForms use a mediatype for XML application that includes binary files and binary attachments. So by default, XForms sends an HTTP command with the following in it:

 mediatype="application/xml"

However most simple web services do not support binary. The mediatype for ASCII text (without binary) is just:

 mediatype="text/xml"

So if you will also be sending binary files you will need to add a mediatype attribute to to your submission:

 <xf:submission mediatype="application/xml"...

Debugging Response Documents[edit]

You can also replace the entire document with the XML result (the option is repace="all") or you can just have it replace an instance.

The last three <toggle> statements are for displaying results.