XForms/Print version

< XForms


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.


Guest Registry

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

Template Organization-NameEdit

  • 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 CollegeEdit

  • 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 AgencyEdit

  • 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 DivisionEdit

  • 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 InstitutionEdit

  • 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, ChinaEdit

  • 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 CentreEdit

  • 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 ConsultingEdit

  • 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.

XeroxEdit

  • 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 SolutionsEdit

  • 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:

IndentationEdit

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 TagsEdit

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 StandardsEdit

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 DOCTYPEEdit

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 MarkupEdit

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 ConventionsEdit

  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 AgenciesEdit

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 WantedEdit

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 ExamplesEdit

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 ExamplesEdit

  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 bookEdit

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 contributorsEdit

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

Focus on Tutorial ExamplesEdit

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 JavaScriptEdit

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.

TestingEdit

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 DuplicationEdit

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 ConventionsEdit

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

BackgroundEdit

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 GraphEdit

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 XFormsEdit

  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 XFormsEdit

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-sayersEdit

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 OptionsEdit

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 PluginEdit

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 ProcessorsEdit

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:

IndentationEdit

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 TagsEdit

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 StandardsEdit

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 DOCTYPEEdit

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 MarkupEdit

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 ConventionsEdit

  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 AgenciesEdit

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

MotivationEdit

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

MethodEdit

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 ProductEdit

Product Name and Current VersionEdit

LicenseEdit

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 UsersEdit

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/BothEdit

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

Browsers SupportedEdit

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

XForms 1.1 Compatibility TestsEdit

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 SupportedEdit

Options would be 1.0, 1.1

Key Limitations of Current ReleaseEdit

Status of XForms Compatibility TestEdit

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 TableEdit

Client Side ApplicationsEdit

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 ApplicationsEdit

(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 MotivationEdit

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 ImageEdit

XForms-hello-world.jpg

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

Link to Working ExampleEdit

Hello World

Hosted *hello world* example

ProgramEdit

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>

ProblemsEdit

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.

DiscussionEdit

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.

ExperimentEdit

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

MotivationEdit

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 ImageEdit

Here is a screen image with the ephemeral message showing:

Link to working XForms ApplicationEdit

Simple Messages

Sample ProgramEdit

<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>

DiscussionEdit

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 ArchitectureEdit

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 InputEdit

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 ApplicationEdit

Input Fields

Program StructureEdit

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 ProgramEdit

<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>

HintsEdit

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

DiscussionEdit

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.

ReferencesEdit

W3C XForms specification for input control

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

Home: XForms



Incremental Many to One

MotivationEdit

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 ApplicationEdit

Load XForms Application

Sample CodeEdit

<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>

DiscussionEdit

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 ModelEdit

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 ImageEdit

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 ApplicationEdit

Spreadsheet-like Updating

Sample ProgramEdit

<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>

DiscussionEdit

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 ImprovementsEdit

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

MotivationEdit

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 ImageEdit

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 ProgramEdit

<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>

DiscussionEdit

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 attributesEdit

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

MotivationEdit

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 ImageEdit

XForms Adder Example After Execution

Link to XForms ApplicationEdit

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 ProgramEdit

<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>

DiscussionEdit

Next Page: Input | Previous Page: Bind

Home: XForms



Input

Basic Form InputEdit

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 ApplicationEdit

Input Fields

Program StructureEdit

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 ProgramEdit

<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>

HintsEdit

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

DiscussionEdit

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.

ReferencesEdit

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 ApplicationEdit

Load XForms Application

ProgramEdit

<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>

DiscussionEdit

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 FieldsEdit

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 ImageEdit

XForms-address-aligned.jpg

Link to XForms ApplicationEdit

Address Aligned

ProgramEdit

<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>

DiscussionEdit

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:leftEdit

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

MotivationEdit

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 ImageEdit

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

Sample ProgramEdit

<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>

DiscussionEdit

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 controlEdit

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 ImageEdit

Here is what the user interface would look like:

Login Screen Using HTML Fieldset and Legend Formatting

Sample ProgramEdit

<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>

TestingEdit

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

DiscussionEdit

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

MotivationEdit

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 ImageEdit

Here is a sceen image with the ephemeral message showing:

XForms-message-types.jpg

Link to working XForms ApplicationEdit

Simple Messages

Sample ProgramEdit

<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>

DiscussionEdit

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

MotivationEdit

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.

MethodEdit

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 ImageEdit

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 SheetEdit

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 ProgramEdit

<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>

DiscussionEdit

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 labelsEdit

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

MotivationEdit

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 ImageEdit

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 ProgramEdit

<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;
}

DiscussionEdit

ReferencesEdit

Next Page: Checkbox | Previous Page: Textarea

Home: XForms



Checkbox

MotivationEdit

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.

MethodEdit

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 ImageEdit

Boolean Checkbox Using Input Control

Link to XForms ApplicationEdit

Load XForms Application

Sample ProgramEdit

<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

MotivationEdit

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.

MethodEdit

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 ImageEdit

XForms Select1 with appearance set to full

Link to Working XForms ExampleEdit

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 ProgramEdit

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>

TestingEdit

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 HorizontalEdit

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>

DiscussionEdit

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.

AcknowledgmentsEdit

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

MotivationEdit

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

MethodEdit

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 ImageEdit

select1 control

Link to Working ApplicationEdit

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 CodeEdit

<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>

DiscussionEdit

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

MotivationEdit

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.

MethodEdit

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

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

Screen ImageEdit

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 ApplicationEdit

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>

DiscussionEdit

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 ButtonsEdit

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 ImageEdit

XForms select with multiple selections and appearance="full"

XForms ApplicationEdit

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 ProgramEdit

<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 AttributeEdit

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

TestingEdit

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

MotivationEdit

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 ImageEdit

XForms-select-multi-column.jpg

Link to Working ExampleEdit

Select Multi Column

Sample ProgramEdit

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 DataEdit

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>

DiscussionEdit

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

MotivationEdit

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

MethodEdit

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

Source CodeEdit

<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

MotivationEdit

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 ImageEdit

XForms-select-from-model.jpg

Execute Sample XForms ApplicationEdit

Load XForms Application

Sample ProgramEdit

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>

DiscussionEdit

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

MotivationEdit

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 serviceEdit

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 InstanceEdit

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

Loading Codes from a Web ServiceEdit

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 InstanceEdit

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 ImageEdit

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 ProgramEdit

<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 DataEdit

<?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 serviceEdit

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 InstanceEdit

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 InstanceEdit

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 Select1Edit

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 RegistryEdit

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.

DiscussionEdit

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

MotivationEdit

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 ImageEdit

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 ApplicationEdit

Date Selector

Sample ProgramEdit

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>

TestingEdit

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.

DiscussionEdit

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

MotivationEdit

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 ImageEdit

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

Link to XForm ExampleEdit

Link to Date Format External Example

Sample ProgramEdit

<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>

DiscussionEdit

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

MotivationEdit

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 ImageEdit

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 ElementEdit

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

Sample ProgramEdit

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>

DiscussionEdit

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 FilesEdit

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 UnencodingEdit

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 FormEdit

<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 FileEdit

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

WarningsEdit

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

ReferencesEdit


Next Page: Trigger | Previous Page: Formatting a date

Home: XForms



Trigger

MotivationEdit

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 ImageEdit

A simple XForm button and the resulting message

Sample ProgramEdit

<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>

DiscussionEdit

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 TriggerEdit

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 EventsEdit

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>

ReferencesEdit

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.

ProgramEdit

<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>

DiscussionEdit

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

NOTEEdit

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

MotivationEdit

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

Selecting from a continuous range of valuesEdit

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 InterfaceEdit

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 ApplicationEdit

Basic Range

Ranges Using Binds

Sample User InterfaceEdit

<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>

TestingEdit

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.

DiscussionEdit

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 SpecificationEdit

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


Next Page: Send | Previous Page: Controlling Button Appearance

Home: XForms



Send

MotivationEdit

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 elementEdit

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 UsageEdit

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

MotivationEdit

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

UsageEdit

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 StringsEdit

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 templatesEdit

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 ExamplesEdit

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

MotivationEdit

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

MotivationEdit

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

MethodEdit

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 ImageEdit

Example of error on bind

Sample CodeEdit

   <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

MotivationEdit

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.

MethodEdit

We will use a bind constraint.


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

Sample Source CodeEdit

<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

MotivationEdit

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

MethodEdit

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 TextareaEdit

<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

MotivationEdit

StepsEdit

Step 1: Add instances for outgoing and incoming dataEdit

<!-- 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 modelEdit

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 inputEdit

<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 invalidEdit

<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/falseEdit

If there are no errors just return <ok/>

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



Submit

The Submit ElementEdit

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 ImageEdit

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

XForms save button

Sample ProgramEdit

<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>

AnalysisEdit

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.

DiscussionEdit

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 ConfigurationEdit

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 DAVEdit

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 ConfigurationEdit

To be done...

ReferencesEdit


Next Page: Encoding Parameters | Previous Page: Case Validation

Home: XForms



Encoding Parameters

MotivationEdit

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

MethodEdit

Changing the Separator CharacterEdit

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 ParameterEdit

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"

DiscussionEdit

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

Home: XForms



Changing Namespaces in Submission

MotivationEdit

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

MethodEdit

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 FormEdit

<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 FilesEdit

With Default NamespaceEdit

<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 PrefixesEdit

<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 ExampleEdit

Example Introduction to XForms 1.1 Submission Differences

Next Page: Events Overview | Previous Page: Encoding Parameters

Home: XForms



Displaying Save Results

MotivationEdit

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.

MethodEdit

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 XQueryEdit

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

MotivationEdit

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

MethodEdit

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 TypesEdit

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 FileEdit

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

MotivationEdit

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.

MethodEdit

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 ApplicationEdit

Load XForms Application

Source CodeEdit

<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

MotivationEdit

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.

MethodEdit

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

Screen ImageEdit

Logging tab selection and deselection events

Sample CodeEdit

<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>

DiscussionEdit

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

MotivationEdit

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

MethodEdit

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>

AcknowledgmentsEdit

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




Binds to many instances

MotivationEdit

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 ImageEdit

Binding to instances in multiple models

Sample ProgramEdit

<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>

DiscussionEdit

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

MotivationEdit

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 ImageEdit

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 ProgramEdit

<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>

DiscussionEdit

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"/>

ReferencesEdit

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.

OutputEdit

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.

ProgramEdit

<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>

DiscussionEdit

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

MotivationEdit

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.

MethodEdit

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

Sample XML FragementEdit

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 ItemsEdit

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 ItemsEdit

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 ApplictionEdit

Load XForms Application

Source CodeEdit

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>

DiscussionEdit

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

MotivationEdit

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 "$#,###.##".

MethodEdit

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 CodeEdit

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

ReferencesEdit

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

MotivationEdit

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.

MethodEdit

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>

DiscussionEdit

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 loadEdit

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 ApplicationEdit

Load XForms Application

Sample ProgramEdit

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>

AcknowledgmentEdit

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

Using Submit and Submission for LinksEdit

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

MotivationEdit

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

Screen ImageEdit

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 ApplicationEdit

Switch and Case

Sample ProgramEdit

<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>

DiscussionEdit

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.

ReferencesEdit

Next Page: Relevant | Previous Page: Output and Links

Home: XForms



Relevant

Using Bind with the Relevant AttributeEdit

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 ApplicationEdit

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

Bind to a DecimalEdit

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 BindsEdit

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 BooleanEdit

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 1Edit

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 statementEdit

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 RulesEdit

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 DisplayEdit

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>

DeleteEdit

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.

DiscussionEdit

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

Home: XForms



Binding in Repeats

MotivationEdit

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

MethodEdit

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 DataEdit

<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 RepeatEdit

<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 BindsEdit

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 ElementEdit

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 ExampleEdit

<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

MotivationEdit

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

MethodEdit

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 ImagesEdit

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 CodeEdit

<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

MotivationEdit

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

MethodEdit

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 ImageEdit

Form without Delete button
Form with Delete button visible

Link to XForms ApplicationEdit

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 attributeEdit

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>

ContextEdit

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 MaxEdit

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>


DiscussionEdit

Next Page: Read Only | Previous Page: Relevant

Home: XForms



Read Only

MotivationEdit

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 ImageEdit

XForm read-only fields have a gray background

Sample ProgramEdit

XHTML XFormEdit

<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;
}

DiscussionEdit

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

Home: XForms



Select and Group

MotivationEdit

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 ImageEdit

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 ProgramEdit

<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>

DiscussionEdit

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.

ReferencesEdit

Next Page: Dynamic Labels | Previous Page: Read Only

Home: XForms



Dynamic Labels

MotivationEdit

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 ImageEdit

Examples of XForms Dynamic Labels

Link to Working XForms ApplicationEdit

XForms Example of Dynamic Labels

Sample ProgramEdit

<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>

DiscussionEdit

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>

CreditsEdit

This example was originally inspired by Kurt Cagle.

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

Home: XForms



Suggesting Items

MotivationEdit

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.

MethodEdit

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 ImageEdit

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 ApplicationEdit

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 ProgramEdit

<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>

DiscussionEdit

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 ValueEdit

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 XQueryEdit

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 ApplicationEdit

Load Non-logging XForms Application

Version with no loggingEdit

<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 AppearanceEdit

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 SearchesEdit

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>

DiscussionEdit

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

MotivationEdit

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

MethodEdit

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 ImageEdit

Cascading Selects

Link to XForms ApplicationEdit

Load Example XForms Application

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

Sample ProgramEdit

<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 ChangesEdit

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

MotivationEdit

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.

MethodEdit

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 ImageEdit

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 ApplicationEdit

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 ReloadsEdit

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 CodeEdit

<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 SamplesEdit

[people.xml] [places.xml] [things.xml]



Dynamic Labels in Local language

MotivationEdit

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 ImageEdit

Local lang english.pngLocal lang hindi.pngLocal lang tamil.png

Sample ProgramEdit

<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>

CreditsEdit

This example was originally inspired by Kurt Cagle.



Search Form

MotivationEdit

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.

DiscussionEdit

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.

MethodEdit

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 ImageEdit

Sample Google Search Form

Link to XForms ApplicationEdit

Load XForms Application

Sample ProgramEdit

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 ListingEdit

<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>

DiscussionEdit

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

MotivationEdit

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 CodeEdit

<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>

DiscussionEdit

Note that you must use the xf:value attribute of the resource element.



Advanced Search

MotivationEdit

You want a simple search function and a separate advanced search options tab.

Source CodeEdit

<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>

DiscussionEdit

Next Page: Pie Chart | Previous Page: Dynamically Load JavaScript

Home: XForms



Date Range Search

MotivationEdit

You want to limit search results based on one or more dates within items.

MethodEdit

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 TableEdit

<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

MotivationEdit

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.

WarningsEdit

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 ImageEdit

File:XForms-flickr.jpg
Search results from flickr using tag "XForms"

Link to XForms ApplicationEdit

Load Form

Sample ProgramEdit

<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>

DiscussionEdit

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 ExploreEdit

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]

ReferencesEdit

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 EventEdit

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 ProgramEdit

The program consists of several parts.

In the model:

  1. The SOAP submission instance
  2. The submission
  3. The SOAP response placeholder

SOAP input messageEdit

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 InstanceEdit

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 StatementEdit

<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.

MediatypeEdit

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 DocumentsEdit

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.

A style sheetEdit

This makes the error messages red and the correct responses green.

 <style type="text/css">
     @namespace xf url("http://www.w3.org/2002/xforms");
     body {font-family: Helvetica, sans-serif}
     .code {font-family: Courier New, fixed-width; font-weight:bold;}
     .error-message {font-weight:bold; color: red}
     .ok {font-weight:bold; color: green}
     xf|output {font-weight:bold; font-size: 16pt}
  </style>

The PresentationEdit

Here is the actual body of the XForms document. It has a single button that calls the web service.

 <body>
    <h1>Web Service Demo</h1>
         <p>Note: With some browsers (FireFox) you must add the appropriate
         hosts to your XForms "white list" for this application to run.
         With FireFox see Tools/Options/Content tab.</p>
     <xf:submit submission="call-web-service">
         <xf:label>Call Web Service</xf:label>
     </xf:submit>  
     <hr/>
     <p>Current form status:</p>
     <xf:switch>
        <xf:case id="case-start">Status: Ready to call web service.</xf:case>
        <xf:case id="case-busy">Waiting for response...please stand by...</xf:case>
        <xf:case id="case-submit-error">
           <p class="error-message">Submission error. Did you remember to allow XForms to submit data to other domains?</p>
        </xf:case>
        <xf:case id="case-done">
           <p class="ok">Results returned successfully</p>
           <xf:group model="my-model">
             <xf:output ref="instance('results-instance')/env:Body/m:my-results/result">
               <xf:label>Return value: </xf:label>
             </xf:output>
           </xf:group>
         </xf:case>
      </xf:switch>
   </body>

DiscussionEdit

The presentation conditionally displays the error messages using a switch/case section. The toggle elements are each triggered by the appropriate event.

You can also put a spinning GIF icon in the section to get an animation for a response from the server.


Next Page: Stock Quote | Previous Page: Search flickr

Home: XForms



Stock Quote

MotivationEdit

You want to have a web page that looks up a stock symbol. You have a REST-based web service that returns stock information if you pass it a ticker symbol. URL that you sends the service looks like the following:

 http://www.webservicex.net/stockquote.asmx/GetQuote?symbol=GOOG

This URL returns the following XML:

 <string>
   <StockQuotes>
     <Stock>
       <Symbol>GOOG</Symbol>
       <Last>472.63</Last>
       <Date>11/9/2006</Date>
       <Time>4:00pm</Time>
       <Change>-2.37</Change>
       <Open>476.33</Open>
       <High>479.49</High>
       <Low>471.86</Low>
       <Volume>4864589</Volume>
       <MktCap>143.8B</MktCap>
       <PreviousClose>475.00</PreviousClose>
       <PercentageChange>-0.50%</PercentageChange>
       <AnnRange>331.55 - 491.96</AnnRange>
       <Earns>7.875</Earns>
       <P-E>60.32</P-E>
       <Name>GOOGLE</Name>
     </Stock>
   </StockQuotes>
 </string>

Sample ProgramEdit

To be done

DiscussionEdit

Next Page: Search Amazon | Previous Page: Web service

Home: XForms



Search Amazon

MotivationEdit

Here is an example web service provided by Amazon. It also uses the custom control to bind images from the output to the screen.

Screen ImageEdit

XForms-search-amazon.jpg

Link to XForms ApplicationEdit

Load Form

Sample ProgramEdit

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
   xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
   <title>Searching Amazon</title>
   <xf:model id="mQuery">

         <xf:instance id="iQuery">
            <instanceData xmlns="">
               <t>webservices-20</t>
               <!-- please get your own key for any production work -->
               <dev-t>D1723OX2631XW0</dev-t>
               <KeywordSearch>xforms</KeywordSearch>
               <mode>books</mode>
               <type>lite</type>
               <page>1</page>
               <f>xml</f>
            </instanceData>
         </xf:instance>

         <xf:instance id="iResults">
            <instanceData xmlns=""/>
         </xf:instance>

         <xf:bind id="bndResults" nodeset="instance('iResults')/Details"/>

         <xf:submission
          id="subAmazonQuery"
          action="http://xml.amazon.com/onca/xml3"
          method="get"
          separator="&amp;"
          ref="instance('iQuery')"
          replace="instance"
          instance="iResults"
          omit-xml-declaration="yes"/>

         <xf:submission
          id="subTestAmazonQuery"
          action="http://xml.amazon.com/onca/xml3"
          method="get"
          separator="&amp;"
          ref="instance('iQuery')"
          replace="all"/>
      </xf:model>

      <!--Mozilla XForms Custom Control for binding images from results -->
    <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="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>
    <style type="text/css">
      @namespace xf url(http://www.w3.org/2002/xforms);
      body {
         font-family: Helvetica, sans-serif;
      }
      <!-- Bind the custom control to output with class="image" -->
      xf|output.image {
        -moz-binding: url('#output-image');
      }
      </style>
   </head>
   <body>
   <h1>Search Amazon With XForms Web Service</h1>
           <xf:input ref="KeywordSearch">
              <xf:label>Search string: </xf:label>
           </xf:input>
           <hr/>
           <xf:submit submission="subAmazonQuery">
              <xf:label>Search Amazon</xf:label>
           </xf:submit>
           <xf:submit submission="subTestAmazonQuery">
              <xf:label>Show results as XML</xf:label>
           </xf:submit>
           <xf:repeat bind="bndResults">
              <xf:output class="image" value="ImageUrlSmall"/>
              <xf:trigger appearance="minimal" style="cursor: hand;">
                  <xf:output ref="ProductName"><xf:label>Title: </xf:label></xf:output>
                  <br/>
                  <xf:output ref="Authors/Author"><xf:label>Author: </xf:label></xf:output>
                 <xf:load ev:event="DOMActivate" ref="@url" show="new"/>
              </xf:trigger>
              <br/>
              <hr/>
           </xf:repeat>
   </body>
</html>

DiscussionEdit

Note: If you get the following error:

XML Parsing Error: not well-formed
Line Number 33, Column 23:
          separator="&"

You will have to remember to escape the ampersand before after you copy and paste this example into your text editor. You can get around this by doing a copy from the edit panel or just putting the following into the separator field:

separator="&amp;"

ReferencesEdit

This program was based on an example provided by formsPlayer [6].


Next Page: Custom Controls | Previous Page: Stock Quote

Home: XForms



Incremental Find

MotivationEdit

You want to show a sample list of search keywords as the user types them into a search field.

MethodEdit

Sample CodeEdit

<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>Wikipedia Open Search Test Form</title>
    <xf:model>
	<xf:instance>
            <root xmlns="">
                <search/>
            </root>
	</xf:instance>

        <!-- the search results are loaded into this instance and have the form item/item due to JSON arrays -->
	<xf:instance id="results">
                <root xmlns=""/>
	</xf:instance>

        <!-- this checks the input value is in the results regardless of lowercases or uppercases -->
	<xf:bind nodeset="search" constraint="instance('results')/item[2]/item[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz') = translate(current(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')]"/>

	<xf:submission id="s1" method="get" replace="instance" instance="results" serialization="none" mode="synchronous">
	   <xf:resource value="concat('http://en.wikipedia.org/w/api.php?action=opensearch&amp;format=json&amp;search=',search)"/>
	</xf:submission>

        <!-- this puts the cursor in the search field when the form loads -->
	<xf:setfocus ev:event="xforms-ready" control="search"/>
      </xf:model>
   </head>
   <body>
      <h1>Wikipedia Open Search Test Form</h1>
      <p>Please enter a subject in the following field. The value is not case sensitive but it has to exist in the results of the corresponding search.</p>

      <xf:input id="search" ref="search" incremental="true">
         <xf:label>Search: </xf:label>
         <!-- for each key press send the s1 search out -->
         <xf:send submission="s1" ev:event="xforms-value-changed"/>
      </xf:input>

      <xf:repeat nodeset="instance('results')/item[2]/item">
	 <xf:output value="."/>
      </xf:repeat>

  </body>
</html>

AcknowledgmentsEdit

This example was created by Alain Couthures of agencexml.com



CKEditor

MotivationEdit

You want to be able to add HTML markup to a textarea.

MethodEdit

We will use the CKEditor JavaScript libraries. This demo was done using version 3.2.

Steps:

  1. Download the source code from: CKEditor web site.
  2. Uncompress the zip file on your local file system
  3. Change any occurrences of "&" to & a m p ; and remove & n b s p ; and & c o p y ; in the HTML files to make the files well formed XHTML files so that eXist can index them. The following files in the 3.2 release will need to be modified:
    1. ckeditor/CHANGES.html
    2. ckeditor/_source/plugins/wsc/dialogs/ciframe.html
    3. ckeditor/_source/plugins/wsc/dialogs/tmpFrameset.html
    4. ckeditor/plugins/wsc/dialogs/ciframe.html
    5. ckeditor/plugins/wsc/dialogs/tmpFrameset.html
  4. Drag the main ckeditor folder into eXist. It should immediately index all html files and store all non-XML files (javascript, css etc.) as binaries.
  5. Note: this does not seem to be possible. Change the Configuration file to not encode the XML.


Failure to follow these step 3 above will result in the following error message:

   XMLDB exception caught:
   Failed to invoke method parse in class org.exist.xmlrpc.RpcConnection:
   org.xml.sax.SAXParseException: The entity name must immediately follow the '&' in the entity reference.


This can be attempted by editing the config.js file.(see Config File Parameters )

  1. Add the following line to config.js
    1. config.HtmlEncodeOutput = 'false';
  2. Replace the sample_postdata.php with the following sample_postdata.xq

Sample XQuery to Echo Post DataEdit

In the _samples folder you will find several samples of how to use CKEditor. Each of these HTML files has an HTML form with the following line:

  <form action="sample_posteddata.xq" method="post">

The following program can be used as a substitute for the sample_postdata.php file.

sample_postdata.xq

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

(: Get the content of the editor1 parameter :)
let $editor1 := request:get-parameter('editor1', '')

(: wrap the content in a div to make sure we have well-formed XML :)
let $wrapped-content := concat('&lt;div&gt;', $editor1, '&lt;/div&gt;')

(: parse the escaped text so that we now have true XML markup :)
let $data-to-save := util:parse($wrapped-content)
return
<results>
  {$data-to-save}
</results>

Configuration File for XML SystemsEdit

CKEditor has a very large number of configuration options. They are set by editing the config.js file in the main CKEditor directory.

The following changes to the CKEditor configuration file should work but it does not seem to have the correct behavior.

config.js

CKEDITOR.editorConfig = function( config )
{
   // Define changes to default configuration here. For example:
   // config.language = 'fr';
   // config.uiColor = '#AADC6E';
	
   // This should turn off encoding of the XML files as they are sent to the server
   config.HtmlEncodeOutput = false;
   config.entities = false;
};



Slideshow

MotivationEdit

You want to have a region of your page that changes images when the user selects a button.

MethodEdit

Store a list of links to the slide images in an instance. Use another instance variable to store the state of the images is currently selected. Use a trigger to update the image number.

Link to XForms ApplicationEdit

Load XForms Application

Sample Source CodeEdit

<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>Slide Show</title>
        <xf:model id="data-model">
            <xf:instance id="data" xmlns="">
                <links>
                    <link href="http://www.bav-astro.de/sterne/monv838/monv838-hubble-20040304.jpg">Image 1</link>
                    <link href="http://aether.lbl.gov/Images/resizenowmap.jpg">Image 2</link>
                    <link href="http://www.nasa.gov/images/content/143744main_hubble_spiral_2006.jpg">Image 3</link>
                    <link href="http://www.space.gc.ca/asc/img/sci_core-hubble.jpg">Image 4</link>
                </links>
            </xf:instance>
            <xf:bind nodeset="instance('data')/link/@href" type="xs:anyURI"/>
            <xf:instance id="state" xmlns="">
                <state>
                    <cycle>0</cycle>
                </state>
            </xf:instance>
            <xf:action ev:event="cycle-next">
                <xf:setvalue ref="instance('state')/cycle" value="(. + 1) mod 4"/>
                <xf:dispatch name="update-model" target="data-model"/>
            </xf:action>
            <xf:action ev:event="update-model">
                <xf:rebuild/>
                <xf:recalculate/>
                <xf:revalidate/>
                <xf:refresh/>
            </xf:action>
        </xf:model>
    </head>
    <body>
        <xf:trigger>
            <xf:label>Next</xf:label>
            <xf:action ev:event="DOMActivate">
                <xf:dispatch name="cycle-next" target="data-model"/>
            </xf:action>
        </xf:trigger>
        <xf:output ref="instance('state')/cycle"/>) <xf:output ref="instance('data')/link[1 + instance('state')/cycle]"/>
        <br/>
        <xf:output ref="instance('data')/link[1 + instance('state')/cycle]/@href" mediatype="image/*"/>
    </body>
</html>

DiscussionEdit

This program has the Next trigger calls the "cycle-next" named event when it is pressed. This event, which is defined in the model, updates the cycle and resets it back to one after the slides are done. After that it instructs the form to recalculate its dependency graph. This updates the visible image.

Note that the output must have a the mediatype set to be image/* for the browser to render the link as an image correctly.

AttributionEdit

This example was created by Chris Wallace and the University of Western England.

Next Page: Referencing Items | Previous Page: Suggesting Items

Home: XForms



Referencing Items

MotivationEdit

You wish to associate a form with a set of items. Once an item is referenced it should not be referenced again.

For example if you have a form that edits tasks you may want to associate a specific task with one or more projects. Once a project is associated with a task you want to remove it from the candidate list of projects it can be associated with.

The way to visualize this is to imagine a set divided into two distinct subsets: selected and un-selected items. As an item moves from the un-selected item set to the selected item set it must first be added to the new set and then deleted from the old set.

MethodEdit

This example uses a combination of the repeat and the switch/case. The currently referenced items are listed in a repeat loop. A button called "Add Reference" uses the toggle function to reveal a list of unselected items. As you select an item it is added to the selected list.

Sample ProgramEdit

<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>Form References</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 xmlns="" id="unreferenced-items">
            <data>
               <reference>
                   <reference-id>1</reference-id>
                   <reference-name>Reference 1</reference-name>
               </reference>
               <reference>
                   <reference-id>2</reference-id>
                   <reference-name>Reference 2</reference-name>
               </reference>
               <reference>
                   <reference-id>3</reference-id>
                   <reference-name>Reference 3</reference-name>
               </reference>
                <reference>
                   <reference-id>7</reference-id>
                   <reference-name>Reference 7</reference-name>
               </reference>
                <reference>
                   <reference-id>8</reference-id>
                   <reference-name>Reference 8</reference-name>
               </reference>
                <reference>
                   <reference-id>9</reference-id>
                   <reference-name>Reference 9</reference-name>
               </reference>
            </data>
          </xf:instance>
          <xf:instance xmlns="" id="referenced-items">
            <data>
               <reference>
                   <reference-id>4</reference-id>
                   <reference-name>Reference 4</reference-name>
               </reference>
                <reference>
                   <reference-id>5</reference-id>
                   <reference-name>Reference 5</reference-name>
               </reference>
                <reference>
                   <reference-id>6</reference-id>
                   <reference-name>Reference 6</reference-name>
               </reference>
            </data>
          </xf:instance>
       </xf:model>
    </head>
    <body>
       <h3>Demonstration of Referencing External Items in an XForms Application</h3>
      <xf:group class="group-label">
          <xf:label>Currently Referenced Items:</xf:label>
           <xf:repeat nodeset="instance('referenced-items')/reference">
              <xf:output ref="reference-name"/>
           </xf:repeat>
           <xf:switch>
           <xf:case id="init">
              <xf:trigger>
                  <xf:label>Add Reference</xf:label>
                  <xf:toggle case="add-reference" ev:event="DOMActivate"/>
              </xf:trigger>
                 <xf:input ref="my-element">
                    <xf:label>Reference Name: </xf:label>
                 </xf:input>
             </xf:case>
             <xf:case id="add-reference">
                 <xf:label>Un-Referenced Items:</xf:label>
                 <xf:repeat nodeset="instance('unreferenced-items')/reference" id="unreferenced-item-repeat">
                  <xf:trigger>
                     <xf:label><xf:output ref="reference-name"/></xf:label>
                     <xf:action ev:event="DOMActivate">
                        <xf:insert nodeset="instance('referenced-items')/reference" at="last()" position="after"/>
                        <xf:setvalue 
                           ref="instance('referenced-items')/reference[last()]/reference-name" 
                           value=" instance('unreferenced-items')/reference[index('unreferenced-item-repeat')]/reference-name "/>
                           <xf:setvalue 
                           ref="instance('referenced-items')/reference[last()]/reference-id" 
                           value=" instance('unreferenced-items')/reference[index('unreferenced-item-repeat')]/reference-id "/>
                        <xf:delete nodeset="instance('unreferenced-items')/reference" at="index('unreferenced-item-repeat')"/>
                     </xf:action>
                  </xf:trigger>
                 </xf:repeat>
             </xf:case>
             </xf:switch>
         </xf:group>
    </body>
</html>

DiscussionEdit

The unreferenced items are not displayed unless the user selects the "Add Reference" trigger. When the user selects the Add Reference trigger the list of currently unreferenced items is displayed.

When the user selects the trigger of an unreferenced item a new item is added to the end of the referenced items list and removed from the unreferenced items list.

This pattern can be used in many examples. For example when you create a custom report you are presented with a list of columns to display. These columns are either referenced in the display list or not referenced.

The user interface sometimes shows these lists side-by-side. This can be accomplished by adding a class to each of the groups and using CSS to display the lists side-by-side.

The one problem with this example is the inability to place the items in the correct order after they are moved to a new list. Hopefully a future version of XForms will support this.


Next Page: Dynamic Selection Lists | Previous Page: Slideshow

Home: XForms



Deep Copy with Insert Origin

MotivationEdit

You want to add a new instance or element from a template. You want to do a deep copy of complex XML from one instance to another instance within a model.

MethodEdit

We will use the XForms xf:insert element with the origin attribute set to the source instance. We will use the nodeset attribute to indicate where the data should be copied to.

Link to XForms ApplicationEdit

Load XForms Application

Source CodeEdit

<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>Using Origin to do a Deep Copy between instances</title>
          <style type="text/css">
               @namespace xf url("http://www.w3.org/2002/xforms");
               body {font-family:Helvetica, sans-serif}
               #source-repeat {border: blue solid 1px;}
               #destination-repeat {border: green solid 1px;}
          </style>
          <xf:model>
               
               <xf:instance xmlns="" id="source">
                    <data>
                         <a>A1</a>
                         <a>A2</a>
                         <a>A3</a>
                    </data>
               </xf:instance>
               
               <xf:instance xmlns="" id="destination">
                    <data/>
               </xf:instance>
               
          </xf:model>
     </head>
     <body>
          <h1>Example of deep copy using XForms insert origin</h1>
          
          <h3>Source:</h3>
          <xf:repeat id="source-repeat" nodeset="instance('source')/a">
               <xf:output ref="."/>
          </xf:repeat> 
          
          <h3>Destination:</h3>
          <xf:repeat id="destination-repeat" nodeset="instance('destination')/a">
               <xf:output ref="."/>
          </xf:repeat> 
               
          <xf:trigger>
               <xf:label>Copy data from source to destination</xf:label>     
               <xf:action ev:event="DOMActivate">
                        <xf:insert
                             origin="instance('source')"                        
                             nodeset="instance('destination')"/>
               </xf:action>
          </xf:trigger>
          
     </body>
</html>


DiscussionEdit

Next Page: Incremental Model Loading | Previous Page: Dynamic Selection Lists

Home: XForms



A Trigger for Inserting BBcode into a Textarea box

Using Trigger to Add BBcode or Other Text to Input or Textarea ControlsEdit

Here is a simple way to use a button (trigger) to add commonly used text to your xforms-input or xforms-textarea controls. This could be many things such as BBcode (bold/unbold codes), date-time stamps, frequently used formatted text such as a letterhead, signature blocks, special codes that aren't easy to remember-- all depending on the purpose of your form and your specific needs.

Link to working XForms ApplicationEdit

Load Example XForms Application


A more advanced example for inserting at the beginning or end of text (with some additional code inserts such as links and images)

Load Example XForms Application

Program StructureEdit

For simplification, we are using a single <text/> element in our model/instance to hold our example input. The style is not really necessary other than to give one a larger text area to test with.

The real power, and simplicity, of the form is in the value attribute of the xforms-setvalue element which itself is placed inside an xforms-trigger:

  value="concat(//text,'whatever you desire goes here')"

Sample ProgramEdit

  <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>Insert BB code</title>
        <style type="text/css">  
        @namespace xf url('http://www.w3.org/2002/xforms');
        xf|textarea .xf-value{ width:25em; height:20ex; }
        </style>
     <xf:model>
        <xf:instance>
               
              <text/>
           
        </xf:instance>
     </xf:model>
  </head>
  <body>
     <xf:trigger><xf:label>Bold</xf:label>
        <xf:action ev:event="DOMActivate">
           <xf:setvalue ref="//text" value="concat(//text,'[b][/b] ')"/> 
           <xf:setfocus control="textArea"/>     
        </xf:action>
     </xf:trigger>
<xf:textarea id="textArea" ref="//text"> <xf:label>Post:</xf:label> </xf:textarea> </body> </html>

DiscussionEdit

This solution will only append the inserted code/text to the end of the current text in the text box. To have it always at the beginning, simply change the order of the arguments in your concat function (see the second example link above).

Limitation: This solution cannot insert code/text into the middle of the current text in the text box.


You can use html entities to do complex formats like a letterhead (if you need to preserve space or bold etc..) (!!note: the ampersand-& is replaced by the percent-% as I couldn't figure out how to escape html entities in this wikibook)

  <xf:setvalue ref="//text" value="concat(//text,'
     %lt;div xmlns=%quot;http://www.w3.org/1999/xhtml%quot;%gt;
        %lt;p%gt;%lt;b%gt;Testing insert with HTMLentities%lt;/b%gt;
        %lt;/p%gt;
        %lt;p%gt;%lt;i%gt;Testing Insertwith HTMLenitites%lt;/i%gt;
        %lt;/p%gt;
        %lt;pre%gt;     Indent Here%lt;/pre%gt; 
     %lt;/div%gt;')"/>

In such a case, make sure your xforms-output has a mediatype attribute like so:

  <xf:output ref="//text" mediatype="application/xhtml+xml"/>

DiscussionEdit

Next Page: Multiple model comparison | Previous Page: Incremental Model Loading

Home: XForms



Multi-Part Forms

MotivationEdit

You have a very large form and your initial load times are very long. You want to be able to break a large form into multiple forms.

MethodEdit

To get the first part of a large form to load we will break the form into multiple parts and only load what appears to be the first tab of a multi-part form. When the user selects the second tab we will save all the data on the first tab and load the second tab. This way if the user want to only make a simple change to the form only the logic for a single tab needs to be loaded.

ExampleEdit

We will use a series of triggers that are styled as file tabs. Each trigger will perform two actions: it will run a save submission and it will then load the next part of the form. The forms will be styled so that it will appear to the user they are just changing tabs.

Here is the sample code from each of the triggers:

<xf:trigger appearance="minimal" class="tab2">
    <xf:label>Part 2</xf:label>
    <xf:action ev:event="DOMActivate">
        <xf:send submission="save"/>
        <xf:load resource="edit-2.xhtml" show="replace"/>
    </xf:action>
</xf:trigger>



Moving Items Between Lists

MotivationEdit

You have two lists and you would like to move selected items between the lists. This is typically known as a column chooser.

MethodEdit

The user interface will have two lists, one on the right and one on the left. Between the lists we will see two buttons; Move Left and Move Right. The user can check any number of items on the left list and press the Move Right button to move these items to the right list. The user can also add any number of items on the right list and then by pushing the Move Left button, these items would be moved to the left list.

Note that a "move" is technically two separate operations, a copy followed by a delete. But the user does not see these separate steps.

Sample Screen ImageEdit

Screen Image of Moving Items Between Lists

Link to Working FormEdit

Link to Working Form

Sample List InstancesEdit

    <left-list>
        <item>Item One</item>
        <item>Item Two</item>
        <item>Item Three</item>
        <item>Item Four</item>
        <item>Item Five</item>
    </left-list>
    <right-list>
        <item>Item Six</item>
        <item>Item Seven</item>
        <item>Item Eight</item>
        <item>Item Nine</item>
        <item>Item Ten</item>
   </right-list>

Sample XFormsEdit

The following form has three columns. One for the left list of items, one for the middle column of move buttons and one for the right list of items.

The Move buttons have two actions.

  1. insert a new item in the list by doing a copy of the selected item to the opposite list
  2. delete the selected item
<div class="left span-3">
     <h3>Left</h3>
     <xf:repeat nodeset="instance('save-data')/left-list/item" id="left-repeat">
        <xf:output ref="."/>
     </xf:repeat>
     
     <xf:output value="index('left-repeat')">
        <xf:label>Left Index: </xf:label>
     </xf:output>
</div>


<div class="middle span-3">
     <xf:trigger>
         <xf:label>Move Right</xf:label>
         <xf:action ev:event="DOMActivate">
            <xf:insert nodeset="instance('save-data')/right-list/item" 
                       origin="instance('save-data')/left-list/item[index('left-repeat')]" 
                       at="last()" position="after" />
            <xf:delete nodeset="instance('save-data')/left-list/item[index('left-repeat')]" />
            
         </xf:action>
     </xf:trigger>
     <xf:trigger>
         <xf:label>Move Left</xf:label>
         <xf:action ev:event="DOMActivate">
            <xf:insert nodeset="instance('save-data')/left-list/item" 
                       origin="instance('save-data')/right-list/item[index('right-repeat')]" 
                       at="last()" position="after" />
            <xf:delete nodeset="instance('save-data')/right-list/item[index('right-repeat')]" />
            </xf:action>
     </xf:trigger>
</div>

<div class="right span-3">
     <h3>Right</h3>
     <xf:repeat nodeset="instance('save-data')/right-list/item" id="right-repeat">
        <xf:output ref="."/>
     </xf:repeat>
     
      <xf:output value="index('right-repeat')">
        <xf:label>Right Index: </xf:label>
     </xf:output>
</div>

Sample CSSEdit

The "span-3" tags use the standard blueprint framework to span three columns in a 24 column page.

The other CSS tags are used below with XSLTForms. Note that the selected item on the list is white.

        @namespace xf url("http://www.w3.org/2002/xforms");
        .left, .middle, .right {border: solid gray 1px; background-color: lavender;}
        .xforms-repeat-item-selected {color: blue; background-color: white;}

DiscussionEdit

The list on the right side could also be re-orderable. This is typically a use-case for a report-writing tools that allows a user to select columns from a list for a report.



Queue Management

MotivationEdit

You want to manage a queue of items and be able to move items around the queue. Sample operations are move up, move down and move to top.

Screen ImageEdit

The up arrow will move the selected row up one item. The down arrow will move the selected item down one item. The triangle will move the selected item to the top of the queue.

Screen Image of Queue Manager

Link to Working ExampleEdit

Link to working example

Sample CodeEdit

Sample Model for Queue Manager:

<xf:model>
    <xf:instance id="save-data" xmlns="">
        <queue>
           <item>
              <id>1</id>
              <title>Item One Title</title>
           </item>
           <item>
              <id>2</id>
              <title>Item Two Title</title>
           </item>
           <item>
              <id>3</id>
              <title>Item Three Title</title>
           </item>
           <item>
              <id>4</id>
              <title>Item Four Title</title>
           </item>
           <item>
              <id>5</id>
              <title>Item Five Title</title>
           </item>
        </queue>
    </xf:instance>
    
    <xf:instance xmlns="" id="views">
        <data>
            <delete-topic-trigger/>
            <tmp/>
        </data>
    </xf:instance>
    
    <xf:bind id="delete-topic-trigger" nodeset="instance('views')/delete-topic-trigger" 
        relevant="instance('save-data')/item[2]"/>
        
</xf:model>

Sample XForms Body CodeEdit

<xf:repeat nodeset="instance('save-data')/item" id="id-repeat">
  <div class="row1">
     <span class="row">
          <xf:output ref="title" class="title"/>              
     </span>
     <xf:input ref="id" class="id"/> 
    
    <xf:trigger>
        <xf:label><img src="images/up.png" alt="Move Up" height="23" width="23"></img></xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:setvalue ref="instance('views')/tmp" value="index('id-repeat')"/> 
            <xf:insert origin="instance('save-data')/item[index('id-repeat')]" 
                       nodeset="instance('save-data')/item" at="index('id-repeat')-1" position="before"/>
           <xf:delete nodeset="instance('save-data')/item[instance('views')/tmp +1]"/>  
        </xf:action>
    </xf:trigger>
    
    <xf:trigger>
        <xf:label><img src="images/down.png" alt="Move Down" height="23" width="23"></img></xf:label>
        <xf:action ev:event="DOMActivate">
             <xf:setvalue ref="instance('views')/tmp" value="index('id-repeat')"/> 
            <xf:insert origin="instance('save-data')/item[index('id-repeat')]" 
                       nodeset="instance('save-data')/item" at="index('id-repeat') +1"/>
            <xf:delete nodeset="instance('save-data')/item[instance('views')/tmp]"/>   
        </xf:action>
    </xf:trigger>
    
    <xf:trigger>
        <xf:label><img src="images/top.png" alt="Move to Top" height="23" width="23"></img></xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:setvalue ref="instance('views')/tmp" value="index('id-repeat')"/>   
            <xf:insert origin="instance('save-data')/item[index('id-repeat')]" nodeset="instance('save-data')/item[1]" at="1" position="before"/>          
            <xf:delete nodeset="instance('save-data')/item[instance('views')/tmp + 1]"/> 
        </xf:action>
    </xf:trigger>
    
     <xf:trigger bind="delete-topic-trigger">
        <xf:label>Delete</xf:label>
        <xf:delete nodeset="instance('save-data')/item[index('id-repeat')]" ev:event="DOMActivate"/>
     </xf:trigger>  
   </div>  
</xf:repeat>

DiscussionEdit

The key to this example is to understand how the insert and delete operations are used with different attributes.

The trigger that moves an item up will need to store its current location in a temporary item.

Note that the current version applies to the highlighted row, not the row that you select the button on.

CreditsEdit

This example contributed by Ann Kelly.

Next Page: none | Previous Page: Moving_Items_Between_Lists

Home: XForms



Horizontal File Tab Menu

Sample Horizontal Tab MenuEdit

This is an example of a horizontal tab menu using CSS and the XForms switch and case statements. Both the tab inside the horizontal tab menu and the div inside the case have the same background color giving the appearance of the selected tab popping to the front of the others.

Screen ImageEdit

You should see a menu that looks similar to this when running under the FireFox browser:

Horizontal tabbox

Note that the tab that is selected has the same color of the content.

Link to XForms ApplicationEdit

Horizontal Tabbox

Sample ProgramEdit

<?xml version="1.0" encoding="UTF-8"?>
<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>XForms Colored Horizontal Tab Menu</title>
        <style>
        @namespace xf url("http://www.w3.org/2002/xforms");
        /* all the attributes of each tab, except the background color */
        body {font-family: Arial, Helvetica, sans-serif;}
        
        /* instructions for styling the horizontal tabs at the top of the form */
        #horiz-tab-menu {
        padding-bottom: 2px;
        }
        #horiz-tab-menu xf|trigger {
            border-left: gray solid 1px;
            border-top: gray solid 1px;
            border-right: gray solid 1px;
            border-bottom: 0px; /* so the tab blends into the region under the tab */
            font-weight: bold;
            font-size: .9em;
            /* spacing between the tabs */
            margin-right: 9px;
            padding: 3px;
            /* round corners at the top of the tab - does not work on older versions of IE */
            -webkit-border-top-left-radius: 5px;
            -webkit-border-top-right-radius: 5px;
            -moz-border-radius-topleft: 5px;
            -moz-border-radius-topright: 5px;
            border-top-left-radius: 5px;
            border-top-right-radius: 5px;
                    }

        /* properties common to all the swapped views */
        #div-1,#div-2,#div-3 {
             width: 500px;
             padding: 5px;
             border-left: solid gray 1px;
             border-right: solid gray 1px;
             border-bottom: solid gray 1px;
        }
        #tab-1, #div-1  {
            background-color: #DDD; /* light gray */
        }
        #tab-2, #div-2  {
            background-color: lightblue;
        }
        #tab-3, #div-3  {
            background-color: khaki;
        }

        </style>
    </head>
    <body>
        <h2>Using switch and case to simulate a tab-view.</h2>
        <div id="horiz-tab-menu">
            <xf:trigger id="tab-1" appearance="minimal">
                <xf:label>Tab 1 Title</xf:label>
                <xf:toggle case="case-1" ev:event="DOMActivate"/>
            </xf:trigger>
            <xf:trigger id="tab-2" appearance="minimal">
                <xf:label>Tab 2 Title</xf:label>
                <xf:toggle case="case-2" ev:event="DOMActivate"/>
            </xf:trigger>
            <xf:trigger id="tab-3" appearance="minimal">
                <xf:label>Tab 3 Title</xf:label>
                <xf:toggle case="case-3" ev:event="DOMActivate"/>
            </xf:trigger>
        </div>
        <xf:switch>
            <xf:case id="case-1" selected="true">
                <div id="div-1">
                    This view is only displayed when tab 1 is selected.<br/>
                    This view is only displayed when tab 1 is selected.<br/>
                    This view is only displayed when tab 1 is selected.<br/>
                    This view is only displayed when tab 1 is selected.<br/>
                </div>
            </xf:case>
            <xf:case id="case-2">
                <div id="div-2">
                    This view is only displayed when tab 2 is selected.<br/>
                    This view is only displayed when tab 2 is selected.<br/>
                    This view is only displayed when tab 2 is selected.<br/>
                    This view is only displayed when tab 2 is selected.<br/>
                </div>
            </xf:case>
            <xf:case id="case-3">
                <div id="div-3">
                    This view is only displayed when tab 3 is selected.<br/>
                    This view is only displayed when tab 3 is selected.<br/>
                    This view is only displayed when tab 3 is selected.<br/>
                    This view is only displayed when tab 3 is selected.<br/>
                </div>
            </xf:case>
        </xf:switch>
        <p>This XForms example shows how the switch and case statements can be
        used to simulate a multi-part form with a row of horizontal tabs at
        the top of the form.  Background colors are used to show which
        tab is the currently selected tab.</p>
    </body>
</html>

TestingEdit

Note that the text under the selected tab changes when you click on the tab.

DiscussionEdit

One of the best ways to reduce your JavaScript is to start converting your menus to use XForms.

This example can be modified to also conditionally display tabs based on state variables in the model.

This example should be made consistent with the XUL tabbox element[7]. If XForms used all the XUL elements this entire example would be much easier to be a standard.

Hopefully XUL and XForms will be consistent in the future.

Using the target pseudo elementEdit

Here is an example that uses the CSS-3 target pseudo element:

W3C Target Example

We could also modify the example to work with XForms.

Using the Non-Standard Attribute Value Templates (AVT)Edit

XForms version 1.0 does not include the ability to put conditional statements within attribute values. Attribute values are text right of the equal sign usually enclosed in double quotes.

Some vendors that have implemented a feature called "AVT" that can be used to conditionally change the values of class attributes. For example:

  <div class="{if (instance('selected-item') = .) then 'selected' else 'not-selected')}">

This effectively will change the style for each tab to use the selected or not-selected style.

Future versions of XForms standards may include AVT functions.

ReferencesEdit

Kurt Cagle's Article on Tabs on XML Today



Horizontal File Tab Menu Highlighted

MotivationEdit

Complex web forms frequently break tasks up into multiple views that can be navigated by the user. These views are access by a set of "file tabs" at the top of a screen. But the user needs feedback on which tab is the current tab and we would like to do this without resorting to complex JavaScript.

Approach: Use the CSS-3 :target pseudo elementEdit

This example uses the CSS-3 :target pseudo element to highlight the selected tab. This tag is associated with the part of a web page that is specified by the label. For example you can append a label to a URL like the following:

http://www.example.com/mypage.html#mylabel

Note: This works only in CSS-3 and will not work under IE-6.

Note that this example is very similar to the prior example but it uses a HTML anchor instead of a trigger.

Screen ImageEdit

Screen image with second tab selected

Sample ProgramEdit

<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>CSS: a tabbed interface</title>
      <style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");

/* Put the tab divs all on one line */
div.horiz-tabs-menu div {
  display: inline;
}		

/* style each individual tab */
div.horiz-tabs-menu div a {
    color: black;
    border: 0.1em outset #BBB;	/* Make it look like a button */
    border-bottom: 0.1em solid #CCC;
    font-weight: bold;
    font-family: Helvetica, sans-serif;
    text-decoration: none;
    margin-right: 5px;
    padding: 0.2em;
    /* round the top corners - works under FireFox */
    -moz-border-radius: .5em .5em 0em 0em;
 }

/* Make non-selected tabs appear in the background */
div.horiz-tabs-menu div:not(:target) a {
   border-bottom: none;		/* Make the bottom border disappear */
   background: #999;
}		

/* Make the selected (targeted) item or default selection to appear on top */
div.horiz-tabs-menu div:target  a {
   border-bottom: 0.1em solid #CCC;   /* Visually connect tab and tab body */
   background: #CCC;                          /* Set active tab to light gray */
}

/* set non-selected tabs to dark gray */
div.horiz-tabs-menu div:not(:target) a {
   border-bottom: none;	/* Make the bottom border disappear */
   background: #999;           /* Set inactive tabs are dark gray */
}

xf|switch xf|case div {
  background: #CCC;		/* Light gray */
  padding: 0.3em;		/* Looks better */
}	
</style>
   </head>
   <body>
      <div class="horiz-tabs-menu">
         <div id="tab1">
            <a  href="#tab1">Tab 1
	         <xf:toggle case="case-1" ev:event="DOMActivate" />
            </a>
         </div>
         <div id="tab2">
            <a href="#tab2">Tab 2
	         <xf:toggle case="case-2" ev:event="DOMActivate" />
            </a>
         </div>
         <div id="tab3">
            <a href="#tab3">Tab 3
	         <xf:toggle case="case-3" ev:event="DOMActivate" />
            </a>
         </div>
      </div>
      <xf:switch>
         <xf:case id="case-1" selected="true()">
            <div>
            1111111111 1111111111 1111111111
            1111111111 1111111111 1111111111
            1111111111 1111111111 1111111111
            1111111111 1111111111 1111111111
            </div>
         </xf:case>
         <xf:case id="case-2">
            <div>
            2222222222 2222222222 2222222222
            2222222222 2222222222 2222222222
            2222222222 2222222222 2222222222
            2222222222 2222222222 2222222222
            </div>
         </xf:case>
         <xf:case id="case-3">
            <div>
            3333333333 3333333333 3333333333
            3333333333 3333333333 3333333333
            3333333333 3333333333 3333333333
            3333333333 3333333333 3333333333
            </div>
         </xf:case>
      </xf:switch>
   </body>
</html>

DiscussionEdit

The selected file-tab should highlight in a light gray. The other menus should be in a dark gray and appear to be more in the background. The content associated with each tab should be visible.

Note that if you want the first tab to highlight on page load, you must use the #tab1 in the URL.]]

Possible areas for improvementEdit

Although this "hack" works and it does get rid of some commonly occurring JavaScript, it is still lacking in several ways.

  1. You can only have a single selected tab on a page.
  2. There is no way to highlight the initial tab without adding the label in the URL
  3. The label gets stuck in the URL and makes things like bookmarking problematic

Ideally XForms would include a :selected pseudo element that would allow you to apply a different style to a selected item within a group. Perhaps someone will do this as a custom control to FireFox.

I should also note I have tried to add a class to the tab1 div called "selected" and added it to the CSS to select it initially, but then it does not unselect when I select a different tab. I can't find an easy way to dynamically add or remove a class to an element in the body of an XForm. There does not appear to be a <xf:class add="selected"> command. Perhaps that will be added to future version of the XForms specification.

Other ExamplesEdit

The following example shows how tab elements can be stored within a model: Kurt Cagle Tab Example

Next Page: Vertical Menu | Previous Page: Horizontal File Tab Menu

Home: XForms



Vertical Menu

MotivationEdit

You want a navigation bar on the left edge of a form that allows you to swap different sections of a large form into view.

Screen ImageEdit

XForms-vertical-tab-menu.jpg

Vertical Tabs

Sample ProgramEdit

<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>CSS: a tabbed interface</title>
      <style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");

/* Make the tab box be on the left */
div.content div.tab-box {
   position: absolute;
   width: 108px;
}

div.tab-box div {
  display: block;
}               

/* style each individual tab */
div.tab-box div a {
   display: block;
    color: black;
    border: 0.1em outset #BBB;  /* Make it look like a button */
    border-right: 0.1em solid #CCC;
    font-weight: bold;
    font-family: Helvetica, sans-serif;
    text-decoration: none;
    text-align: right;
    padding: 0.2em;
    /* round the left corners - works only under FireFox */
    -moz-border-radius: .7em  0em 0em .7em;
    width: 100%;
    line-height: 1.4em;
 }

/* Make non-selected tabs appear in the background */
div.tab-box div:not(:target) a {
   border-bottom: none;         /* Make the right border disappear */
   background: #999;
}               

/* Make the selected (targeted) item or default selection to appear on top */
div.tab-box div:target  a {
   border-bottom: 0.1em solid #CCC;   /* Visually connect tab and tab body */
   background: #CCC;                          /* Set active tab to light gray */
}

/* set non-selected tabs to dark gray */
div.tab-box div:not(:target) a {
   border-bottom: none; /* Make the bottom border disappear */
   background: #999;           /* Set inactive tabs are dark gray */
}

/* style the swapped area */
div.case {
  position: absolute;
  margin-left: 115px;
  background: #CCC;             /* Light gray */
  padding: 0.3em;               /* Looks better */
  width: 400px;
  height: 145px;
}       
</style>
   </head>
   <body>
   <div class="content">
      <div class="tab-box">
         <div id="tab1">
            <a  href="#tab1">Select Items: 
                 <xf:toggle case="case-1" ev:event="DOMActivate" />
            </a>
         </div>
         <div id="tab2">
            <a href="#tab2">Bill To: 
                 <xf:toggle case="case-2" ev:event="DOMActivate" />
            </a>
         </div>
         <div id="tab3">
            <a href="#tab3">Ship To: 
                 <xf:toggle case="case-3" ev:event="DOMActivate" />
            </a>
         </div>
         <div id="tab4">
            <a href="#tab4">Shipping: 
                 <xf:toggle case="case-4" ev:event="DOMActivate" />
            </a>
         </div>
         <div id="tab5">
            <a href="#tab5">Confirmation: 
                 <xf:toggle case="case-5" ev:event="DOMActivate" />
            </a>
         </div>
      </div>  <!-- tabbox -->
      <xf:switch>
         <xf:case id="case-1" selected="true()">
            <div class="case">
            1111111111 1111111111 1111111111
            1111111111 1111111111 1111111111
            1111111111 1111111111 1111111111
            1111111111 1111111111 1111111111
            </div>
         </xf:case>
         <xf:case id="case-2">
            <div class="case">
            2222222222 2222222222 2222222222
            2222222222 2222222222 2222222222
            2222222222 2222222222 2222222222
            2222222222 2222222222 2222222222
            </div>
         </xf:case>
         <xf:case id="case-3">
            <div class="case">
            3333333333 3333333333 3333333333
            3333333333 3333333333 3333333333
            3333333333 3333333333 3333333333
            3333333333 3333333333 3333333333
            </div>
         </xf:case>
         <xf:case id="case-4">
            <div class="case">
            4444444444 4444444444 4444444444
            4444444444 4444444444 4444444444
            4444444444 4444444444 4444444444
            4444444444 4444444444 4444444444
            </div>
         </xf:case>
            <xf:case id="case-5">
            <div class="case">
            5555555555 5555555555 5555555555
            5555555555 5555555555 5555555555
            5555555555 5555555555 5555555555
            5555555555 5555555555 5555555555
            </div>
         </xf:case>
      </xf:switch>
      </div> <!-- content -->
   </body>
</html>

DiscussionEdit

This is similar to the horizontal tab menu. It uses the CSS-3 target pseudo element.

ReferencesEdit

Next Page: Folding Menus | Previous Page: Horizontal File Tab Menu Highlighted

Home: XForms



Storing Tabs in the Model

MotivationEdit

You want to dynamically modify your tabs while the form is executing.

MethodEdit

Rather than statically loading all your tabs in the form body it is also possible to store your tabs in the XForms model and then display each of them by using a repeat.

Full ExampleEdit

declare namespace h = "http://www.w3.org/1999/xhtml";

let $content-type := "text/xml"
let $mode := xdmp:set-response-content-type($content-type)
let $results := 
(
processing-instruction {'xml-stylesheet'} {'type="text/xsl" href="/lib/xsltforms/xsltforms.xsl"'},
<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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
    <head>
        <title>Tabs</title>
        <xf:model id="data-model">
            <xf:instance id="tabset-instance" xmlns="">
                <tabset value="create">
                    <item value="create">Create</item>
                    <item value="configure">Configure</item>
                    <item value="validate">Validate</item>
                    <item value="review">Review</item>
                </tabset>
            </xf:instance>
        </xf:model>
        <style type="text/css"><![CDATA[
body {margin:0.25in;}

.xforms-repeat-item  {
    display:inline-block;
    font-size:12pt;
    font-family:Arial;
    text-align:center;
    padding:5px;
    border:solid 1px black;
    background-color:lightGray;
    -moz-border-radius-topleft:10px;
    -webkit-border-top-left-radius:10px;
    -moz-border-radius-topright:10px;
    -webkit-border-top-right-radius:10px;    
}

/* this formats the selected tab differently so that you can tell what tab you are using */
.xforms-repeat-item-selected {
    border-bottom:solid 3px white;
    background-color:white;
}
.tabframe {
    position:relative;
    }
    
.tabs {
/*    position:absolute;
    z-index:2; */
    margin-left:15px;
    }

.tabpane {
    width:800px;
    height:500px;
    border:solid 1px black;
    z-index:1;
/*    position:absolute; */
    margin-top:-2px;
    padding:10px;
    box-shadow: 7px 7px 8px #818181;
    -webkit-box-shadow: 7px 7px 8px #818181;
    -moz-box-shadow: 7px 7px 8px #818181;
    -moz-border-radius:10px;
    -webkit-border-radius:10px;
    -moz-border-radius:10px;
    -webkit-border-radius:10px;    
    };
        ]]></style>
   </head>
    <body>
        <div class="tabframe">
        <div class="tabs">
        <xf:repeat nodeset="instance('tabset-instance')/item" 
            id="tab-item-repeat">
            <xf:trigger ref="." appearance="minimal"> 
                <xf:label><xf:output ref="."/></xf:label>
                <xf:action ev:event="DOMActivate">
                    <xf:setvalue ref="instance('tabset-instance')/@value" 
                    value="instance('tabset-instance')/item[index('tab-item-repeat')]"/>
                    <xf:toggle ref=".">
                        <xf:case value="@value"/>
                    </xf:toggle>
                </xf:action>
            </xf:trigger>
        </xf:repeat>
        </div>
        <div class="tabpane">
        <xf:switch>
        <xf:case id="create" selected="true">
                <h1>Create Transformation Strategy</h1>
                <p>This is the pane where strategies for transformations are designed</p>
        </xf:case>
        <xf:case id="configure">
                <h1>Configure Strategy Parameters</h1>
                <p>This sets the parameters necessary for the execution of the strategy.</p>
        </xf:case>
        <xf:case id="validate">
                <h1>Validate Strategy Rules</h1>
                <p>This sets up tests for determining whether the transformation has succeeded or failed.</p>
        </xf:case>
        <xf:case id="review">
                <h1>Review Strategy</h1>
                <p>This provides a comprehensive review of the states defined within a given strategy.</p>
        </xf:case>
        </xf:switch>
        </div>
        </div>
    </body>
</html>)
return $results

AcknowledgmentsEdit

This example was posted by Kurt Cagle on XML Today.



Folding Menus

MotivationEdit

You want to display a complex list of choices in a tree structure where each branch could be opened and closed.

Sample ProgramEdit

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Folding Menus</title>
      <xf:model id="modelID" ev:event="" functions="" schema="">
         <xf:instance id="instanceData" xmlns="">
            <group id="mainGroup">
               <group id="group1" fold="0" category="Category One">
                  <item id="item1">Enter Data</item>
                  <item id="item2">Enter Data</item>
                  <item id="item3">Enter Data</item>
                  <group id="group2" fold="0" category="Category Two">
                     <item id="item4">Enter Data</item>
                     <item id="item5">Enter Data</item>
                     <group id="group3" fold="0" category="Category Three">
                        <item id="item6">Enter Data</item>
                        <item id="item7">Enter Data</item>
                        <item id="item8">Enter Data</item>
                     </group>
                     <item id="item9">Enter Data</item>
                  </group>
               </group>
            </group>
         </xf:instance>
         <xf:instance id="foldedNodes" xmlns="">
            <foldednodes>
               <nodelist />
            </foldednodes>
         </xf:instance>

         <xf:bind nodeset="descendant::*"
            relevant="not(contains(instance('foldedNodes')/nodelist, current()/parent::*/@id))"
          />
      </xf:model>

      <style type="text/css">
         @namespace xhtml url("http://www.w3.org/1999/xhtml");
         @namespace xf url("http://www.w3.org/2002/xforms");
         xf|*:disabled {
         display: none;
         }
      </style>

   </head>

   <body>

      <div class="header">Folding Test</div>

      <xf:group id="mainGroup">
         <xf:output ref="instance('foldedNodes')/nodelist">
            <xf:label>ID List</xf:label>
         </xf:output>
         <xf:repeat nodeset="instance('instanceData')/descendant::group" id="repeatGroup">
            <xf:output class="outputInline"
               value="concat(substring('&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;',1,3 * count(current()/ancestor::*)), '&#160;&#160;&#160;&#160;&#160;')" />
            <xf:trigger>
               <xf:label>
                  <xf:output
                     value="if(contains(instance('foldedNodes')/nodelist, ./@id), '+', '-')"
                   />
               </xf:label>
               <xf:action ev:event="DOMActivate">
                  <xf:setvalue ref="instance('foldedNodes')/nodelist"
                     value="if(contains(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id), concat(substring-before(instance('foldedNo