XForms/Print version
This is the print version of XForms You won't see this message or any elements not part of the book's content when you print or preview this page. |
The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
https://en.wikibooks.org/wiki/XForms
Guest Registry
We would like to know who is using this cookbook. Please tell us all little about yourself:
Template Organization-Name
[edit | edit source]- Contact Name:
- Organization:
- Location:
- Use: How are you using the book?
- Like: What did you like the most about the XForms Tutorial and Cookbook? What samples were the most useful?
- Improve: What would you like to see improved in the book? What new examples would you like?
County Community College
[edit | edit source]- Name: County Community College
- Location: New Jersey
- Use: Teaching yourself, teaching others, college classroom, high school etc.
- Like:
I am looking for a working examples that my students could use to build their own XForms applications. I will be using the example in this book to help my students learn about XForms.
US Federal Agency
[edit | edit source]- Name: Federal Agancy
- Location: Washington DC
- Use: Teaching our staff how to build XRX applications and manage TEI documents
- Like: Working progams
- Improve: More sample document workflow application
Minnesota Department of Revenue - Property Tax Division
[edit | edit source]- Name: Dan McCreary
- Location: St. Paul Minnesota
- Use: We are using the cookbook to learn XForms and build property taxation form.
- Like: We like XForms because we can generate them from XML Schemas and we don't need any Java or C# or VB to when we use the eXist native XML database
- Would Like: We would like more examples that use XML Binding (XBL)
A Financial Institution
[edit | edit source]- Location: Minneapolis Minnesota
- Use: We use the cookbook to teach internal staff how to build an maintain forms
- Like: Small working examples. The links are great.
- Would Like: Examples of process management forms and Schematron rules engines using XForms
ZheJiang, China
[edit | edit source]- Name: zhouliyi
- Location: ZheJiang,China
- Use: We are using the cookbook to share XForms examples and document our best practices.
- Like: XForms is great for creating prototypes of our forms.
- Would like: How you create XForms by transforming a source XML Schema information would be very nice.
- Example: Examples that integrate with databases would be great.
NIC - Open Technology Centre
[edit | edit source]- Contact Name: Rajamani M
- Organization: NIC - Open Technology Centre
- Location: India
- Use: We are using the cookbook to share XForms , XRX examples and
developing sample applications.
- Like: We like the XRX sample with Database connected
- Improve: More examples to expand the concept in each element and functions
Drybridge Consulting
[edit | edit source]- Contact Name: Arthur Colman
- Organization: Drybridge Consulting
- Location: Boston, MA USA
- Use: Using the cookbook to upgrade our implementation of XForms and to share examples.
- Like: The broad range of examples.
Xerox
[edit | edit source]- Contact Name: Jacob Woodworth
- Organization: Xerox
- Location: Rochester, NY
- Use: Implementation using XForms.
- Like: The examples I've seen here are the best I've found on the Web.
- Improve: TBD
Grant Solutions
[edit | edit source]- 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 | edit source]If you really like the book please send a postcard to:
Dan McCreary 3007 Cavell Ave. So St. Louis Park, MN 55426
It would be very much appreciated!
Naming Conventions
Here are some naming conventions used for this WikiBook. These naming conventions are designed to be consistent across the sample programs, allowing our students to be able to copy and paste blocks of code from the sample programs with a minimum amount of reformatting. So even though it may be a little bit annoying to have the xf:
prefix on the XForms data elements, it does make it easy for students to quickly build new applications from the samples.
The audiences for much of this material are state and federal agencies that are converting paper forms to electronic forms. As a result we tend to use the XML Naming and Design Guidelines used by these organizations. Since these standards are built around ISO/IEC-11179 and other ebXML standards, they should not be too strange to most business developers.
There are over 150 of "Naming and Design Rule" guidelines but we don't need to use them all. A web site that discusses them is the Component Organization and Registration Environment web site.
Here are some guide lines to start out with:
Indentation
[edit | edit source]Please use three space characters to indent your examples. MediaWiki does not allow us to set tab stops and by default they are 8 characters.
Wrap XML Code in Source Tags
[edit | edit source]Please enclose all your sample XML code with the source tags with the lang="xml" attribute like this:
<syntaxhighlight lang="xml"> ....your XML code here... </syntaxhighlight>
Namespace Standards
[edit | edit source]Namespaces are core to XForms today and essential for our examples to work under a large number of diverse platforms. Please take some time to think carefully about namespaces and namespace prefixes.
Please use the following template at the head of your example:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <head> ...
Note that the first line:
xmlns="http://www.w3.org/1999/xhtml"
indicates that the file uses XHTML as its default namespace. Any tags that do not have a namespace prefix are by default elements in the xhtml namespace.
We feel that keeping the examples in this default namespace will make students familiar with HTML more at home with XForms. Standard tags such as <h1>, <p>, <b> and <i> can be freely used in all our examples.
You can optionally add the XML processing instruction before the <html> tag:
<?xml version="1.0" encoding="UTF-8"?>
but most XForms systems do not need this. Any file that has a file extension of ".xhtml" implicitly implies that it is an XML file.
Warnings about DOCTYPE
[edit | edit source]Please do not put the !DOCTYPE tag in the header for xhtml1-strict.dtd. This specifically states that the file ONLY contains XHTML and most systems will not allow XForms tags when they see this. Many example programs have this and it should be removed to be correct.
XForms Player Specific Markup
[edit | edit source]Please do not put any player-specific markup in the examples. This book is about W3C standards, specifically XForms, CSS, XML Schema and XHTML. These examples should not require a specific implementation of a client forms player. If you are working with a specific player that does require special HTML tags, they can be automatically inserted by the web application server using an XML transform. This allows these examples to be used in a wide variety of classroom environments and by a large number of server and client XForms players.
For a general template see XForms/Template
For player specific instructions see Player Specific Instructions.
List of Example Program Naming Conventions
[edit | edit source]- Use a separate namespace for HTML, XForms controls and Data.
- Give HTML the default namespace. This makes it easy to take existing XHTML code and use it in the examples
- If it is not possible to give HTML a default namespace, give it a namespace prefix that is short, such as "h".
- Use the "xf" namespace prefix for XForm elements. I find about 3/4 of the examples use this already but some use the full "xform" or "xforms" prefix. I suggest avoiding the confusion and just use "xf" since it is short and in common use already.
Examples for US State and Federal Agencies
[edit | edit source]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.
Examples Wanted
Here are some examples were are still looking for:
Examples Wanted
[edit | edit source]Here is list of the example progams we are looking for in rough order of priority (highest priority examples are first)
- Example to format currency - We would like an example that formats based on numeric picture formats such as "$#,###.##".
- 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?
- 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
- 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
- Instance validation - An example based on an external XML schema. Validate an instance using the XML Schema file. Validate
- XMLEvents Demonstrate how XML Events work with event propagation. Show how events bubble up the event responder tree.
- Use industry standard forms (IRS tax forms, ACORD insurance forms etc).
- A XForms example incorporating XML Signing in XHTML preferably with digital filters too.
- Full CRUD Example using any Database Demonstrate the full create, read, update delete (CRUD) cycle for some form data selected from a database. The example load the form data from a database into an instance document and (similar to using the src="" attribute), view the data, edit the data and save the data back to a database using a submit
Non FireFox Examples
[edit | edit source]FireFox does not have Pseudo_element_support for ::value
, ::repeat-item
, and ::repeat-index
.
See Pseudo element support in FireFox
Are their any other systems that will support this that we can get examples from?
Finished Examples
[edit | edit source]- 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
- 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
- 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
- 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.
- 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.
- Set textarea size. Use the CSS to set the area of a textarea size differently of many boxes. See Textarea with style
Book Statistics
Here is a link that has some statistics on this Wikibook:
Current Stats
[edit | edit source]December 2010
[edit | edit source]162 chapters, 885 edits, size 1.2 kB, 39906 words, 71 registered authors
Past Statistics
[edit | edit source]October 2009
[edit | edit source]147 chapters, 1133 edits, size 1.2 kB, 38664 words, 76 registered authors
April of 2009
[edit | edit source]141 chapters, 885 edits, size 3.2 kB, 34874 words, 62 registered authors
In March of 2008
[edit | edit source]116 chapters, 626 edits, size 214 , 28811 words, 29 registered authors
2006
[edit | edit source]Book Created
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:
- an elegant Model-View-Controller (MVC) architecture
- a movement toward declarative programming which is easier to learn, maintain and debug
- a rich set of user interface controls for handling complex things such as dates, numbers and ranges
- compatibility with XML standards such as Cascading Style Sheets (CSS), XML Schema and XPath
- extensibility
XForms can be run today from almost any web browser by either using an downloadable plugin or extension (such as the Firefox extension) or by loading a JavaScript file. For more information see the Benefits section of this book.
About this book
[edit | edit source]This book is intended to be a tutorial and cookbook with many complete running XForms examples. The initial examples are designed to teach the fundamental concepts of XForms. The more advanced examples are designed to solve specific tasks and reduce the amount of JavaScript necessary to write high-quality forms.
We would like to have the examples ordered from simple to complex. At the end of the cookbook there are integration examples of how to extend and integrate XForms with other systems such as web services.
The philosophy behind this book centers around the fact that people often learn best by taking a fully-functioning program and making slight modifications to it to understand how it works.
Guidelines for contributors
[edit | edit source]Please feel free to add your own examples to this tutorial and cookbook! Here are a few suggestions for contributors:
Focus on Tutorial Examples
[edit | edit source]The first set of examples should focus on new XForms users. Please keep tutorials on foundational concepts (XPath and XML Schema) in a separate area so that users already familiar with these concepts can skip these sections.
Focus on Reducing JavaScript
[edit | edit source]One of the goals of this book is to help forms developers move away from hard-to-maintain scripting languages such as JavaScript. Any examples that focus on getting rid of commonly used JavaScript functions are very much appreciated.
Testing
[edit | edit source]Please tell us what XForms systems you have used to test your examples. If you can, we recommend testing using the major browsers (Internet Explorer and Firefox) using either an extension, plug-in or a JavaScript translator such as FormFaces. See also the Installing XForms in Firefox.
We would like to eventually have a small box in the upper right corner that tells what systems each example was tested under.
Avoid Duplication
[edit | edit source]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.
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.
Background
Background
[edit | edit source]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:
- They were either browser or vendor specific solutions to a specific problem
- They did not integrate mainstream developments in XML Schema, XPath and CSS
- They did not take into account the need for clear separation-of-concerns
- 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:
- Model-View-Binding architecture
- Advanced functionality
- Precise specification for all browsers to integrate
- Extensibility without resorting to JavaScript programming
- Built-in assumptions about how form elements get updated
The Dependency Graph
[edit | edit source]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
Benefits
Why XForms?
[edit | edit source]There are many benefits to using XForms over traditional HTML forms. Some of the most frequently mentioned benefits are:
Benefits of XForms
[edit | edit source]- 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
- 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.
- 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.
- Less JavaScript - XForms allows the movement away from hard-to-maintain, difficult to debug and potentially insecure JavaScript
- 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
- Clean and consistent use of MVC architectures
- Forms are easier to create, debug and maintain
- Forms can accommodate multiple languages and multiple currencies
- Forms have clear Separation of Concerns, meaning all your forms can share a common style sheet, model, bindings and presentation.
- Advanced user interface controls such as the XForms/Range control
- Extensibility of XForms (see XForms/Custom Controls)
- 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 tablet. This core philosophy of Separation of Concerns is one of the key elements to the philosophy of XForms and good human-machine interactions.
Disadvantages of XForms
[edit | edit source]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:
- Web browser limitations have made it difficult for XForms tools vendors to support all XForms tags in all browsers
- Slow performance on very-large forms - forms with over 200 fields sometimes can be slow to load on some older browsers
- 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.
- Lack of understanding of XML - Many traditional HTML/JavaScript forms developers are not familiar with XML standards
- Few complete working XForms examples and applications exist (a problem which we are trying to correct with this book)
- Few high-quality and low-cost GUI forms builder tools exist today (with the exception of IBM's Workplace forms, OpenOffice Forms, Onyx Forms and few other tools)
You will note that most of the disadvantages of XForms are related to limitations of XForms clients, current browser shortcomings, or skills and training issues. There are few fundamental architectural disadvantages with XForms.
Analysis of XForms Nay-sayers
[edit | edit source]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
Installing and Testing
XForms Client Options
[edit | edit source]There are several ways to get started using XForms. But we must first understand that running XForms within a web browser has several security-related issues that prevent software from saving to your local hard drive. There are several workarounds for this.
There are several XForms systems that can be used to build XForms. For example:
XSLTForms is a XForms implementation that can run within your browser or on the server. The client-based system run an XSLT transform within your browser.
BetterFORM is a server-side implementation of XForms that comes bundled with a native XML database (eXist-db).
There are JavaScript-based solutions and other plugins as well as web-server solutions available. See the Player Specific Instructions or the wikipedia page on XForms for more details. Note that these XForm solutions usually require you to download a web server and install Java Web Archive Files (War files) in the correct directory or add player-specific code to your examples.
FireFox Plugin
[edit | edit source]The FireFox plugin has limited support on the Mac and may not be supported in current versions of FireFox.
One of the most common today is Installing XForms in Firefox. This takes only about a minute to install so it is used by many of our students. Most of these exercises have been tested with the Firefox 0.7 extension on both Firefox 1.5 and Firefox 2.0.
Firefox 3.6 plugin: xForms 0.8.7
Firefox 2.0 plugin: FireFox 2.0 for the Mac
XForms Processors
[edit | edit source]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
Naming Conventions
Here are some naming conventions used for this WikiBook. These naming conventions are designed to be consistent across the sample programs, allowing our students to be able to copy and paste blocks of code from the sample programs with a minimum amount of reformatting. So even though it may be a little bit annoying to have the xf:
prefix on the XForms data elements, it does make it easy for students to quickly build new applications from the samples.
The audiences for much of this material are state and federal agencies that are converting paper forms to electronic forms. As a result we tend to use the XML Naming and Design Guidelines used by these organizations. Since these standards are built around ISO/IEC-11179 and other ebXML standards, they should not be too strange to most business developers.
There are over 150 of "Naming and Design Rule" guidelines but we don't need to use them all. A web site that discusses them is the Component Organization and Registration Environment web site.
Here are some guide lines to start out with:
Indentation
[edit | edit source]Please use three space characters to indent your examples. MediaWiki does not allow us to set tab stops and by default they are 8 characters.
Wrap XML Code in Source Tags
[edit | edit source]Please enclose all your sample XML code with the source tags with the lang="xml" attribute like this:
<syntaxhighlight lang="xml"> ....your XML code here... </syntaxhighlight>
Namespace Standards
[edit | edit source]Namespaces are core to XForms today and essential for our examples to work under a large number of diverse platforms. Please take some time to think carefully about namespaces and namespace prefixes.
Please use the following template at the head of your example:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <head> ...
Note that the first line:
xmlns="http://www.w3.org/1999/xhtml"
indicates that the file uses XHTML as its default namespace. Any tags that do not have a namespace prefix are by default elements in the xhtml namespace.
We feel that keeping the examples in this default namespace will make students familiar with HTML more at home with XForms. Standard tags such as <h1>, <p>, <b> and <i> can be freely used in all our examples.
You can optionally add the XML processing instruction before the <html> tag:
<?xml version="1.0" encoding="UTF-8"?>
but most XForms systems do not need this. Any file that has a file extension of ".xhtml" implicitly implies that it is an XML file.
Warnings about DOCTYPE
[edit | edit source]Please do not put the !DOCTYPE tag in the header for xhtml1-strict.dtd. This specifically states that the file ONLY contains XHTML and most systems will not allow XForms tags when they see this. Many example programs have this and it should be removed to be correct.
XForms Player Specific Markup
[edit | edit source]Please do not put any player-specific markup in the examples. This book is about W3C standards, specifically XForms, CSS, XML Schema and XHTML. These examples should not require a specific implementation of a client forms player. If you are working with a specific player that does require special HTML tags, they can be automatically inserted by the web application server using an XML transform. This allows these examples to be used in a wide variety of classroom environments and by a large number of server and client XForms players.
For a general template see XForms/Template
For player specific instructions see Player Specific Instructions.
List of Example Program Naming Conventions
[edit | edit source]- Use a separate namespace for HTML, XForms controls and Data.
- Give HTML the default namespace. This makes it easy to take existing XHTML code and use it in the examples
- If it is not possible to give HTML a default namespace, give it a namespace prefix that is short, such as "h".
- Use the "xf" namespace prefix for XForm elements. I find about 3/4 of the examples use this already but some use the full "xform" or "xforms" prefix. I suggest avoiding the confusion and just use "xf" since it is short and in common use already.
Examples for US State and Federal Agencies
[edit | edit source]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.
Comparison of XForms Products
Motivation
[edit | edit source]You want to compare XForms browser products and understand each systems strengths and weaknesses.
Method
[edit | edit source]We first identify key attributes of each product and justify why an attribute is relevant in a high-level comparison. We then present a table of the products with one column for each attribute.
Key Attributes of XForms Product
[edit | edit source]Product Name and Current Version
[edit | edit source]License
[edit | edit source]What type of license is being used? Common options are Commercial (with link), Apache 2.0, LGPL, GPL or other. The column should always provide a URL to the exact license.
Cost Per 10 or 100 or 1,000 or 10,000 Users
[edit | edit source]What is the typical estimated costs for this product for between 10 and 10,000 users. Assume 10 medium-complexity forms used per person per day.
Client/Server/Both
[edit | edit source]Does the product convert the XForms code into browser-specific structures (HTML/JavaScript) on the client or the server?
Browsers Supported
[edit | edit source]What browsers are supported? Common items are All, C, F, I, O, S for Chrome, FireFox, IE, Opera and Safari.
XForms 1.1 Compatibility Tests
[edit | edit source]The W3C does provide a test suite for compatibility with the 1.1 specification. These test are rerun on a periodic basis.
Currently only a subset of products are being tested. The current test results are here
Version of XForms Supported
[edit | edit source]Options would be 1.0, 1.1
Key Limitations of Current Release
[edit | edit source]Status of XForms Compatibility Test
[edit | edit source]Did this product undergo a third party test of all of the features of XForms? If so, what percentage of the test pass. Provide a link to the test results.
Comparison Table
[edit | edit source]Client Side Applications
[edit | edit source]Product (Version) | License | Cost | Implementation | Architecture | Browsers | Test Results | Strength | Weakness | Notes | |
---|---|---|---|---|---|---|---|---|---|---|
EMC/Documentum | Commercial | See Documentum | Google Web Toolkit | Client | All | EMC Results | ||||
Chiba (3.0.0b2) | liberal BSD and Apache 2 | free | Client DOJO with DWR | 96% Chiba Results | ||||||
Ubiquity | Apache 2.0 | free | JavaScript | All | Test Results | Not mature | ||||
Firefox Plugin | Open source | Free | Browser Plugin | Client | Firefox 3.5 and earlier only | [1] | Very compliant with standard | Firefox only, Limited Table Support, Limited Support, No Mac Version | Innovative Product, Ideal for quick prototyping, Fast form loads for forms that do not have long selection lists | |
Formfaces | Commercial | JScript and HTML - No plugin required | Client | Very slow load times for medium forms, No large user base | No updates to product since 2007 | |||||
XSLTForms | LGPL | Free | XSLT Tranformation | Client or Server | All | Transform works on either server or client, Bundled with eXist and MarkLogic | Not yet mature | See XRX Wikibook | ||
Picoforms | Commercial | See Picoforms | IE Plugin | Client | Internet Explorer Only | Ideal for internal forms for IE only sites | Support not clear, Required Admin rights to install Limited Community Support |
Server-Side Applications
[edit | edit source](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. |
HelloWorld
Background and Motivation
[edit | edit source]Since K&R wrote the first book on C programming, it has become tradition for programming books to begin with a "Hello World" program. Running this program will indicate if you have XForms installed correctly.
Here is a sample "hello world" program in XForms. It uses one input, one variable in the model, and one output. You should be able to just copy and paste the text into a program such as Notepad and save it to a file such as hello.htm. This will tell you if you have the Firefox or other browser extension installed correctly.
Screen Image
[edit | edit source](Note that this is only a .jpg and NOT an actual form!)
Link to Working Example
[edit | edit source]Program
[edit | edit source]To run this program, just copy the following text into a file "hello.xhtml" and open it with your web browser with the appropriate XForms extension loaded.
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Hello World in XForms</title>
<xf:model>
<xf:instance xmlns="">
<data>
<PersonGivenName/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>Type your first name in the input box. <br/>
If you are running XForms, the output should be displayed in the output area.</p>
<xf:input ref="PersonGivenName" incremental="true">
<xf:label>Please enter your first name: </xf:label>
</xf:input>
<br />
<xf:output value="concat('Hello ', PersonGivenName, '. We hope you like XForms!')">
<xf:label>Output: </xf:label>
</xf:output>
</body>
</html>
Problems
[edit | edit source]If this program does not work, you may not have the extension or plug-in installed in your browser.
For help see Installing XForms in FireFox.
Note that if you have the NoScript Firefox extension installed, you may need to configure NoScript to allow scripts from the location from which you are loading HelloWorld.
Also note, in Firefox the file has to be saved with a xhtml or xml extension. A file with a .html exension won't show the XForms.
Discussion
[edit | edit source]Note that the file looks much like a standard HTML file with a few exceptions.
- there is a namespace declaration at the beginning of the file and there are two elements with a
xf:
prefix in front of them. - there is something called a model inside the HTML
<head>
element - There are some new elements:
input
andoutput
.
The two important lines are:
<xf:input ref="PersonGivenName" incremental="true"/>
and
<xf:output value="concat('Hello ', PersonGivenName, '. We hope you like XForms!')"/>
As the user types, this line takes the input that the user types in and copies it to the instance variable "PersonGivenName". Each time you type a character this program updates the output and using the XPath concat()
function to wrap the string "Hello " in front of the name and the string ". We hope you like XForms!" after it.
You should also note that there is not a single line of JavaScript required to run this program. Getting rid of JavaScript is one of the biggest reasons people are migrating their applications to XForms.
Experiment
[edit | edit source]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.
Simple Message
Motivation
[edit | edit source]This is a simple message in XForms. The user presses a button and they see an alert panel. This is an example of a modal message, which the user must respond to in order to continue using the form. We will cover two other types of message later.
Screen Image
[edit | edit source]Here is a screen image with the ephemeral message showing:
Link to working XForms Application
[edit | edit source]Sample Program
[edit | edit source]<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 xmlns="">
<data>
<MyMessage xmlns="">This is a modeless message stored directly in the model.
Note you can drag me to the side and still proceed to the next task.</MyMessage>
<inp1/>
<inp2/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>Put your cursor in the first input. A message will appear for just a moment.</p>
<xf:input ref="inp1">
<xf:label>Ephemeral message: </xf:label>
<xf:message level="ephemeral" ev:event="DOMFocusIn">This is an ephemeral message.
Don't worry, I go away after a few seconds.</xf:message>
</xf:input>
<br/>
<p>Press enter in the input field to get a modeless message:</p>
<xf:input ref="inp2">
<xf:label>Modeless message input: </xf:label>
<xf:message level="modeless" model="myModel" ref="/data/MyMessage" ev:event="DOMActivate"/>
</xf:input>
<br/>
<p>A standard and intrusive modal message that must be dismissed:</p>
<xf:trigger>
<xf:label>Press for a modal message</xf:label>
<xf:message level="modal" ev:event="DOMActivate">This is a modal message.</xf:message>
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]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—FIXED
XForms Architecture
The XForms Architecture
[edit | edit source]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.
Input Example
Basic Form Input
[edit | edit source]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.
Link to XForms Application
[edit | edit source]Program Structure
[edit | edit source]Our program has two parts, a model and a view. The model has instance data in it to store the values that the user enters in the form. The view is part of the presentation in the body of the HTML document.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>XForms inputs with labels</title>
<xf:model>
<xf:instance xmlns="">
<data>
<PersonGivenName/>
<PersonSurName/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>Enter your first name, and last name.</p>
<xf:input ref="PersonGivenName" incremental="true">
<xf:label>First Name:</xf:label>
<xf:hint>Also known as given name.</xf:hint>
</xf:input>
<br/>
<xf:input ref="PersonSurName" incremental="true">
<xf:label>Last Name:</xf:label>
<xf:hint>Also known as sur name or family name.</xf:hint>
</xf:input>
<br/>
<br/>
Output First Name: <b><xf:output ref="PersonGivenName"/></b>
<br/>
Output Last Name: <b><xf:output ref="PersonSurName"/></b>
<p>Note that as you type the model output will be updated.</p>
</body>
</html>
Hints
[edit | edit source]You can also provide the user with data entry hints using the <xf:hint> element.
Discussion
[edit | edit source]Notice that as you type, the output gets immediately updated. This is because the XForms input control has an incremental="true"
attribute.
Our model is simple, just the first and last name of a person.
Note that the label
and hint
tags are nested INSIDE the input tags.
References
[edit | edit source]W3C XForms specification for input control
Incremental Many to One
Motivation
[edit | edit source]Sometimes a single input field will be used to create a new output. Not only does the input field need to be updated, but other fields that depend on this input also need to change.
Here is an example program that has three input fields. As an example, it uses a data dictionary entry (called a Data Element). The name of the Data Element is a concatenation of three fields: the Object Class Name, the Property Name and the Representation Term. The first two are text fields and the third is a value that is picked from a list.
This form creates a single output based on the values of the input fields. This shows that the model can take many different inputs and create a single output.
Link to working XForms Application
[edit | edit source]Sample Code
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Many to one</title>
<xf:model>
<xf:instance xmlns="">
<DataElement>
<ObjectClassName />
<PropertyName />
<RepresentationTerm />
</DataElement>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group nodeset="/DataElement">
<fieldset>
<legend>Data Element Name</legend>
<xf:label>DataElementName: </xf:label>
<xf:output value="concat(ObjectClassName, ' ', PropertyName, ' ', RepresentationTerm)"/>
<p>
<xf:input ref="ObjectClassName" incremental="true">
<xf:label>Object Name:</xf:label>
</xf:input>
</p>
<p>
<xf:input ref="PropertyName" incremental="true">
<xf:label>Property Name:</xf:label>
</xf:input>
</p>
<p>
<xf:select1 ref="RepresentationTerm" incremental="true">
<xf:label>Representation Term:</xf:label>
<xf:item>
<xf:label>Amount</xf:label>
<xf:value>Amount</xf:value>
</xf:item>
<xf:item>
<xf:label>Code</xf:label>
<xf:value>Code</xf:value>
</xf:item>
<xf:item>
<xf:label>Count</xf:label>
<xf:value>Count</xf:value>
</xf:item>
<xf:item>
<xf:label>ID</xf:label>
<xf:value>ID</xf:value>
</xf:item>
<xf:item>
<xf:label>Indicator</xf:label>
<xf:value>Indicator</xf:value>
</xf:item>
<xf:item>
<xf:label>Name</xf:label>
<xf:value>Name</xf:value>
</xf:item>
<xf:item>
<xf:label>Percent</xf:label>
<xf:value>Percent</xf:value>
</xf:item>
<xf:item>
<xf:label>Text</xf:label>
<xf:value>Text</xf:value>
</xf:item>
</xf:select1>
</p>
</fieldset>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]How can you then take that output and put it back into the model? This will be covered later in the tutorial.
Spreadsheet-like Updating
Updating the Model
[edit | edit source]Many developers of traditional JavaScript-based forms are not accustomed to variables automatically updating for them. With XForms, you can easily create a complex system where XForms automatically figures out what cells to update. This is similar to using a spreadsheet. A dependency graph is automatically created for you and the appropriate cells are automatically updated if an input they depend upon changes.
Here is an example program that demonstrates this.
Screen Image
[edit | edit source]Here is a screen capture of the application:
Note that top grid is actually just unlabeled input cells. Below that is a sample output inside a table. You should be able to change any of the input cells, enter a tab, and see the output and the footer calculations change.
Link to Working XForms Application
[edit | edit source]Sample Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>XForms Spreadsheat like Update</title>
<style type="text/css">
table {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
}
th {
color: white;
background-color: black;
}
.output tr td {
border: solid black 1px;
padding: 2px;
text-align: center;
}
</style>
<xf:model>
<xf:instance>
<Spreadsheet xmlns="">
<Row>
<A>10</A>
<B>20</B>
<C>30</C>
</Row>
<Row>
<A>40</A>
<B>50</B>
<C>60</C>
</Row>
<Row>
<A>70</A>
<B>80</B>
<C>90</C>
</Row>
<Results>
<sum/>
<avg/>
<min/>
</Results>
</Spreadsheet>
</xf:instance>
<xf:bind nodeset="/Spreadsheet/Results/sum" calculate="sum(/Spreadsheet/Row/A)" type="xs:decimal" />
<xf:bind nodeset="/Spreadsheet/Results/avg" calculate="avg(/Spreadsheet/Row/B)" type="xs:decimal" />
<xf:bind nodeset="/Spreadsheet/Results/min" calculate="min(/Spreadsheet/Row/C)" type="xs:decimal" />
</xf:model>
</head>
<body>
<xf:group ref="/Spreadsheet">
<xf:input ref="Row[1]/A">
<xf:label></xf:label>
</xf:input>
<xf:input ref="Row[1]/B">
<xf:label></xf:label>
</xf:input>
<xf:input ref="Row[1]/C">
<xf:label></xf:label>
</xf:input>
<br/>
<xf:input ref="Row[2]/A">
<xf:label></xf:label>
</xf:input>
<xf:input ref="Row[2]/B">
<xf:label></xf:label>
</xf:input>
<xf:input ref="Row[2]/C">
<xf:label></xf:label>
</xf:input>
<br/>
<xf:input ref="Row[3]/A">
<xf:label></xf:label>
</xf:input>
<xf:input ref="Row[3]/B">
<xf:label></xf:label>
</xf:input>
<xf:input ref="Row[3]/C">
<xf:label></xf:label>
</xf:input>
<table class="output">
<thead>
<tr>
<th>#</th>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<xf:output value="1" />
</td>
<td>
<xf:output ref="Row[1]/A" />
</td>
<td>
<xf:output ref="Row[1]/B" />
</td>
<td>
<xf:output ref="Row[1]/C" />
</td>
</tr>
<tr>
<td>
<xf:output value="2" />
</td>
<td>
<xf:output ref="Row[2]/A" />
</td>
<td>
<xf:output ref="Row[2]/B" />
</td>
<td>
<xf:output ref="Row[2]/C" />
</td>
</tr>
<tr>
<td>
<xf:output value="3" />
</td>
<td>
<xf:output ref="Row[3]/A" />
</td>
<td>
<xf:output ref="Row[3]/B" />
</td>
<td>
<xf:output ref="Row[3]/C" />
</td>
</tr>
<tr>
<td />
<td>Sum=<xf:output ref="Results/sum" />
</td>
<td>Avg=<xf:output ref="Results/avg" />
</td>
<td>Min=<xf:output ref="Results/min" />
</td>
</tr>
</tbody>
</table>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]Due to limitations with some of the XForms implementations this example does not use the "repeat" command but just addresses each cell directly by its address.
Suggested Improvements
[edit | edit source]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.
Bind
Motivation
[edit | edit source]There are three core concepts that you will learn in building XForms applications:
- The model is a tree of data elements
- The presentation is a tree of data elements
- To build your form, these two trees need to be wired together - this is called "binding"
Many of the exercises in this cookbook give examples of this binding. This process is a small example of how this can work. In practice there are many ways to bind the user interface to the model.
Screen Image
[edit | edit source]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.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<head>
<title>Your Title Here</title>
<xf:model>
<xf:instance xmlns="">
<data>
<PersonGivenName/>
<PersonSurName/>
</data>
</xf:instance>
<xf:bind id="PersonGivenName" nodeset="/data/PersonGivenName"/>
<xf:bind id="PersonSurName" nodeset="/data/PersonSurName"/>
</xf:model>
</head>
<body>
<xf:input bind="PersonGivenName" incremental="true">
<xf:label>Input First Name:</xf:label>
</xf:input>
<br/>
<xf:input bind="PersonSurName" incremental="true">
<xf:label>Input Last Name:</xf:label>
</xf:input>
<br/>
<xf:output bind="PersonGivenName">
<xf:label>Output First Name:</xf:label>
</xf:output>
<br/>
<xf:output bind="PersonSurName">
<xf:label>Output Last Name:</xf:label>
</xf:output>
</body>
</html>
Discussion
[edit | edit source]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 <b>bind="PersonGivenName"</b>>
We should also note that in this case there is a single input and a single output for each data element. This does not need to be the case. A single input can be bound to many outputs and an output could also depend on many inputs. An example of this would be using the "calculate" attribute of the bind statement.
Bind attributes
[edit | edit source]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
Adder
Motivation
[edit | edit source]This program demonstrates several different ways to call a web service from a sample XForms application. The example uses both HTTP POST and HTTP GET methods and shows how the results are returned into an instance in the model and how the page can be replaced with the results. The web service it calls is a simple web service that adds two numbers together.
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]For the results to be put in the model using FireFox, make sure to add www.sa.kw.ua.sa
and xforms-examples.google.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.
Sample Program
[edit | edit source]<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="&">
<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="&">
<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="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="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="&"
action="http://xformstest.org/cgi-bin/showinstance.sh"/>
<xf:submission id="post-test" method="post" replace="all"
action="http://xformstest.org/cgi-bin/showinstance.sh"/>
</xf:model>
</head>
<body>
<h1>Using XForms to test XQuery</h1>
<p>Note, you must have xforms-examples.googlecode.com and www.cems.uwe.ac.uk in your whitelist for this demo to work.</p>
<xf:input ref="arg1" incremental="true">
<xf:label>Arg1:</xf:label>
</xf:input>
<xf:input ref="arg2" incremental="true">
<xf:label>Arg2:</xf:label>
</xf:input>
<xf:output ref="instance('submit-results')/sum">
<xf:label>Sum:</xf:label>
</xf:output>
<xf:submit submission="get-instance">
<xf:label>HTTP GET -> instance</xf:label>
</xf:submit>
<br/>
<xf:submit submission="post-instance">
<xf:label>HTTP POST -> instance</xf:label>
</xf:submit>
<br/>
<xf:submit submission="get-replace">
<xf:label>HTTP GET -> replace</xf:label>
</xf:submit>
<br/>
<xf:submit submission="post-replace">
<xf:label>HTTP POST -> replace</xf:label>
</xf:submit>
<br/>
<xf:submit submission="get-test">
<xf:label>HTTP Get Test</xf:label>
</xf:submit>
<br/>
<xf:submit submission="post-test">
<xf:label>HTTP Post Test</xf:label>
</xf:submit>
<br/>
<xf:switch>
<xf:case id="ready"/>
<xf:case id="case-busy">
<p>Waiting for results from server...</p>
</xf:case>
<xf:case id="case-submit-error">
<p>Submit error</p>
</xf:case>
<xf:case id="case-submit-done">
<p>Submit done</p>
</xf:case>
</xf:switch>
</body>
</html>
Discussion
[edit | edit source]
Input
Basic Form Input
[edit | edit source]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.
Link to XForms Application
[edit | edit source]Program Structure
[edit | edit source]Our program has two parts, a model and a view. The model has instance data in it to store the values that the user enters in the form. The view is part of the presentation in the body of the HTML document.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>XForms inputs with labels</title>
<xf:model>
<xf:instance xmlns="">
<data>
<guru/>
<PersonSurName/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>Enter your first name, and last name.</p>
<xf:input ref="PersonGivenName" incremental="true">
<xf:label>Input First-Name:</xf:label>
<xf:hint>Also known as given name.</xf:hint>
</xf:input>
<br/>
<xf:input ref="PersonSurName" incremental="true">
<xf:label>Input Last Name:</xf:label>
<xf:hint>Also known as sur name or family name.</xf:hint>
</xf:input>
<br/>
<br/>
Output First Name: <b><xf:output ref="PersonGivenName"/></b>
<br/>
Output Last Name: <b><xf:output ref="PersonSurName"/></b>
<p>Note that as you type the model output will be updated.</p>
</body>
</html>
Hints
[edit | edit source]You can also provide the user with data entry hints using the <xf:hint> element.
Discussion
[edit | edit source]Notice that as you type, the output gets immediately updated. This is because the XForms input control has an incremental="true"
attribute.
Our model is simple, just the first and last name of a person.
Note that the label
and hint
tags are nested INSIDE the input tags.
References
[edit | edit source]W3C XForms specification for input control
Address
Here is a simple address form. Note that HTML is the default namespace. We interleave both XForms and HTML tags but the XForms tags have xf as a prefix. We use the HTML fieldset and legend tags to put related form elements in a group. We use the XForms group element to tell us where in the model to get our instance data.
Link to XForms Application
[edit | edit source]Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Address Form</title>
<xf:model>
<xf:instance>
<Address xmlns="">
<LocationStreetFullText />
<LocationCityName />
<LocationStateName />
<LocationPostalID />
</Address>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group ref="/Address">
<fieldset>
<legend>Mailing Address</legend>
<xf:input ref="LocationStreetFullText">
<xf:label>Street: </xf:label>
</xf:input>
<br />
<xf:input ref="LocationCityName">
<xf:label>City:</xf:label>
</xf:input>
<br />
<xf:input ref="LocationStateName">
<xf:label>State:</xf:label>
</xf:input>
<br />
<xf:input ref="LocationPostalID">
<xf:label>Postal Code:</xf:label>
</xf:input>
</fieldset>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]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.
Address Aligned
Using CSS to Align Form Fields
[edit | edit source]Forms are much easier to use if they are aligned. This example uses CSS table structures to align our form. It turns groups into tables, inputs into rows and labels and values into cells.
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Address Form Aligned Using CSS</title>
<style type="text/css"><![CDATA[
/* a stylesheet for X-Forms input field alignment */
@namespace xf url("http://www.w3.org/2002/xforms");
/* give the input form labels and the fieldset legend a bold sans-serif font */
label, legend {
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
}
/* give the fieldset some breathing room */
fieldset {
padding: 5px;
width: 260px;
}
/* the labels are right-aligned in a 150px wide column */
xf|label {
width: 150px;
margin: 3px;
text-align: right;
}
/* the input values are left aligned */
xf|value {
text-align: left;
}
/* vertical area between input boxes */
input {
margin: .2em;
}
/* each group is our table */
xf|group {
display: table;
}
/* each input is a row in the group table */
xf|input {
display: table-row;
}
/* each label within an input is a cell in the input row */
xf|input xf|label {
display: table-cell;
}
/* each value (pseudo-element) is also a cell in the input row */
xf|input::value {
display: table-cell;
}
]]>
</style>
<xf:model>
<xf:instance xmlns="">
<Address>
<LocationStreetFullText />
<LocationStreetFullText2 />
<LocationCityName />
<LocationStateName />
<LocationPostalID />
</Address>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group>
<fieldset>
<legend>Mailing Address</legend>
<xf:input ref="LocationStreetFullText">
<xf:label>Street: </xf:label>
</xf:input>
<xf:input ref="LocationStreetFullText2">
<xf:label />
</xf:input>
<xf:input ref="LocationCityName">
<xf:label>City:</xf:label>
</xf:input>
<xf:input ref="LocationStateName">
<xf:label>State:</xf:label>
</xf:input>
<xf:input ref="LocationPostalID">
<xf:label>Postal Code:</xf:label>
</xf:input>
</fieldset>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]This style sheet only covers the XForms <xf:input> tags. It will need additions if you want to align select, select1, textarea and other controls. A full CSS file for doing this is described later on in this cookbook.
Note that you MUST put inputs inside of a group element for this stylesheet to work.
Also note that the table can grow if the labels get too long.
Note that the display: table properties work in FireFox but may not work in older browsers that do not support table layout.
Alternative layout strategy using float:left
[edit | edit source]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.
Input Field Width
Motivation
[edit | edit source]Sometimes you want to be able to control the field width, even though the default input text scrolls. This can be done for the entire form or for on a field-by-field basis for all input fields within a form. For example if you have three places that a person's last name occurs they can all be controlled by changing a single CSS file that is imported into the form. This CSS file can also be generated directly from an XML Schema or metadata registry using XML transforms.
Screen Image
[edit | edit source] <fieldset name="image_info" legend="Image Information">
<field name="subjectWeight" type="text" label="Subject Weight:" maxlength="10" size="15" /><label="Kg">
</filedset>
Discussion
[edit | edit source]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.
Secret
The XForms secret control
[edit | edit source]People that are sitting near you should not be able to see your password as you enter it. The secret
control echos a "*" to the screen for each character you type.
Screen Image
[edit | edit source]Here is what the user interface would look like:
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Sample XForms Login</title>
<style type="text/css"><![CDATA[
@namespace xf url("http://www.w3.org/2002/xforms");
xf|group {
display: table;
}
xf|input, xf|secret {
display: table-row;
}
xf|value {
text-align: left;
}
xf|label, legend {
display: table-cell;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
text-align: right;
width: 100px;
}
]]>
</style>
<xf:model>
<xf:instance xmlns="">
<Login>
<LoginID />
<Password />
</Login>
</xf:instance>
</xf:model>
</head>
<body>
<fieldset>
<legend>System Login</legend>
<xf:input ref="LoginID">
<xf:label>Login: </xf:label>
</xf:input>
<br />
<xf:secret ref="Password">
<xf:label>Password: </xf:label>
</xf:secret>
</fieldset>
</body>
</html>
Testing
[edit | edit source]The login characters should be echoed back but the password field should just echo a "*" character for every character the user types.
Discussion
[edit | edit source]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;">
Message Types
Motivation
[edit | edit source]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:
- ephemeral - a message that just appears briefly and goes away by itself
- modeless - a message you can ignore for now
- modal - a message the user must acknowledge before you go on
Screen Image
[edit | edit source]Here is a sceen[check spelling] image with the ephemeral message showing:
Link to working XForms Application
[edit | edit source]Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
>
<head>
<title>XForms Message</title>
<xf:model id="myModel">
<xf:instance>
<MyMessage xmlns="">This is a modeless message stored directly in the model.
Note you can drag me to the side and still proceed to the next task.
</MyMessage>
</xf:instance>
</xf:model>
</head>
<body>
<p>Put your cursor in the first input. A message will appear for just a moment.</p>
<xf:input>
<xf:label>Ephemeral message: </xf:label>
<xf:message level="ephemeral" ev:event="DOMFocusIn">This is an ephemeral message.
Don't worry, I go away after a few seconds.</xf:message>
</xf:input>
<br/>
<p>Press enter in the input field to get a modeless message:</p>
<xf:input>
<xf:label>Modeless message input: </xf:label>
<xf:message level="modeless" model="myModel" ref="/MyMessage" ev:event="DOMActivate"/>
</xf:input>
<br/>
<p>A standard and intrusive modal message that must be dismissed:</p>
<xf:trigger>
<xf:label>Press for a modal message</xf:label>
<xf:message level="modal" ev:event="DOMActivate">This is a modal message.</xf:message>
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]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.
Textarea
Motivation
[edit | edit source]The user may enter more text than used in a typical single line input field and/or the programmer wants to use a large block of multi-line text to capture user input.
Method
[edit | edit source]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>
</source >
== Screen Image ==
Here is a screen image using the FireFox XForms extension:
[[Image:XForms-textarea.jpg|center|frame|XForms textarea control with label]]
Note that the label is aligned at the bottom of the left edge.
== Sample Style Sheet ==
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.
<syntaxhighlight lang="css">
textarea {
font-family: sans-serif;
height: 8em;
width: 600px;
}
</source >
== Sample Program ==
<syntaxhighlight lang="xml">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>XForms textarea</title>
<xf:model>
<xf:instance xmlns="">
<data>
<MyTextValue />
</data>
</xf:instance>
</xf:model>
</head>
<body>
<xf:input ref="Name" incremental="true">
<xf:label> Name:</xf:label>
</xf:output ref="Name">
<xf:textarea ref="MyTextValue">
<xf:label>Note:</xf:label>
</xf:textarea>
</body>
</html>
Discussion
[edit | edit source]One of the challenges is to be able to format the size of the textarea correctly. This is usually done in a style sheet.
Aligning the labels
[edit | edit source]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;
}
Textarea with style
Motivation
[edit | edit source]The default layout for a textarea is often not what you want. The size of the textarea may not be correct or the label may not be positioned correctly. This program shows you how to change this.
Screen Image
[edit | edit source]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.
Sample Program
[edit | edit source]<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 | edit source]@namespace xf url("http://www.w3.org/2002/xforms"); /* put each textarea on its own row */ xf|textarea { display: table-row; } xf|textarea > xf|label { display: table-cell; font-family: sans-serif; font-size: 10pt; font-weight: bold; vertical-align: top; text-align: right; padding-right: 3px; } textarea { font-family: Courier, sans-serif; } .default-textarea { font-style :regular; } .small-textarea textarea { height: 4.4em; /* a bit less than four lines to demonstrate scrolling */ width: 300px; } .medium-textarea textarea { height: 6em; width: 400px; } .large-textarea textarea { font-family: Courier, sans-serif; height: 10em; width: 500px; } .x-large-textarea textarea { font-family: Courier, sans-serif; height: 20em; width: 700px; }
Discussion
[edit | edit source]References
[edit | edit source]
Checkbox
Motivation
[edit | edit source]You have a boolean true/false value and want an input control to have a simple checkbox for a yes/no or true/false answer.
Method
[edit | edit source]We will use a standard input control but use the bind statement to bind the instance to a boolean datatype. We will do this in two ways, one using a bind without an ID and using the bind with an id so that we can reference the bind statement.
Note that checkboxes can also be demonstrated by using the xf:select control. But in that case a series of space-delimited values is stored in the value associated with the control.
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]<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>
Select1
Motivation
[edit | edit source]You want an input control that allows a user to select one and only one item from a list of possible items. You have enough room on the form to display all the possible values. You would also like what the user sees and what is placed in the instance to be different.
Method
[edit | edit source]Any time you would like the user to make a single selection from a list of possible options you can use the XForms select1
control. There are two variations of this, one to display all the values (also known as a radio-button) and one that presents a drop-down list and thus takes up less screen area.
Each item on the list of possible choices must have an item
and within that it must have a value
and an optional label
. The value is the string that will be inserted into the data element that is referenced using the ref
property. The ref
property points to a data element in your model.
Screen Image
[edit | edit source]Link to Working XForms Example
[edit | edit source]Note that the lower-case value will be displayed under the select1 control to show you how the select1 control is changing the model. Only the labels are shown to the user.
Example Program
[edit | edit source]In the example below, the instance variable MyCode inside MyModel will be set to the value selected by the radio buttons control.
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>XForms Radio Button Usng Select1 appearance="full"</title>
<xf:model>
<xf:instance xmlns="">
<data>
<ColorCode/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>XForms Radio Button Usng Select1 appearance="full"</p>
<xf:select1 ref="ColorCode" appearance="full" >
<xf:item>
<xf:label>Red</xf:label>
<xf:value>red</xf:value>
</xf:item>
<xf:item>
<xf:label>Orange</xf:label>
<xf:value>orange</xf:value>
</xf:item>
<xf:item>
<xf:label>Yellow</xf:label>
<xf:value>yellow</xf:value>
</xf:item>
<xf:item>
<xf:label>Green</xf:label>
<xf:value>green</xf:value>
</xf:item>
<xf:item>
<xf:label>Blue</xf:label>
<xf:value>blue</xf:value>
</xf:item>
</xf:select1>
Output: <xf:output ref="ColorCode"/>
</body>
</html>
Testing
[edit | edit source]You should see all the possible values when you use a full appearance. Each time you click on one of the radio buttons, the value of MyCode in the model will be updated and the output should automatically be updated. Note that the value is displayed (in lowercase), not the label.
Changing the Orientation to Horizontal
[edit | edit source]You can change the radio button to use a horizontal layout by applying float:left style to all the item elements.
In your CSS do the following:
.horiz xf|item {
float: left;
}
In your body wrap all of the xf:item elements in a div with a class="horiz"
<xf:select1 ref="my-element" appearance="full">
<xf:label>Color: </xf:label>
<div class="horiz">
<xf:item>
<xf:label>Red</xf:label>
<xf:value>red</xf:value>
</xf:item>
<xf:item>
<xf:label>Green</xf:label>
<xf:value>green</xf:value>
</xf:item>
<xf:item>
<xf:label>Red</xf:label>
<xf:value>blue</xf:value>
</xf:item>
</div>
</xf:select1>
Discussion
[edit | edit source]You can always change a radio button to a drop down list by just removing the appearance="full"
attribute from the select1 element.
You can also use an XPath expression to display labels and values from the model using the xf:itemset element.
<xf:select1 ref="my-element">
<xf:itemset nodeset="instance('codes')/data/item">
<xf:label ref="label"/>
<xf:value ref="value"/>
</xf:itemset>
</xf:select1>
See the other examples for examples of this.
Acknowledgments
[edit | edit source]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.
Select1 drop list
Motivation
[edit | edit source]You want to allow the user to select a single value from a list.
Method
[edit | edit source]Here is an example of using the select1 to create a drop-down list. The user must pick one and only one from the selected list.
Note that each item has a label (for humans to read) and a value (usually placed within an XML document). Values are typically stored in a database and use to compare to items together. Since values are frequently passed as arguments in a URL in a REST interface the convention is to only use lowercase letters and dashs. Do not put spaces, slashes and other characters in values if you are using REST interfaces. This makes the URLs difficult to read.
Screen Image
[edit | edit source]Link to Working Application
[edit | edit source]Note that when the form is initially loaded, no day of the week is displayed in the input our output. After you press the drop-down list (the back triangle to the right of the input control) and select a day of the week the value will be filled in. A label (the name that starts with the uppercase) will be displayed in the select1 control. The actual version in the model will be the value which is the lower-case version. This is also the version that is displayed in the output.
Source Code
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Demonstration of XForms Select1</title>
<style type="text/css"><![CDATA[body {font-family: Helvetica, sans-serif;}]]></style>
<xf:model>
<xf:instance xmlns="">
<data>
<DayOfWeekCode/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<xf:select1 ref="DayOfWeekCode">
<xf:label>Day of Week:</xf:label>
<xf:item>
<xf:label>Monday</xf:label>
<xf:value>monday</xf:value>
</xf:item>
<xf:item>
<xf:label>Tuesday</xf:label>
<xf:value>tuesday</xf:value>
</xf:item>
<xf:item>
<xf:label>Wednesday</xf:label>
<xf:value>wednesday</xf:value>
</xf:item>
<xf:item>
<xf:label>Thursday</xf:label>
<xf:value>thursday</xf:value>
</xf:item>
<xf:item>
<xf:label>Friday</xf:label>
<xf:value>friday</xf:value>
</xf:item>
<xf:item>
<xf:label>Saturday</xf:label>
<xf:value>saturday</xf:value>
</xf:item>
<xf:item>
<xf:label>Sunday</xf:label>
<xf:value>sunday</xf:value>
</xf:item>
</xf:select1>
<br/>
Output: <xf:output ref="DayOfWeekCode"/>
</body>
</html>
Discussion
[edit | edit source]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.
Open Selection
Motivation
[edit | edit source]You want to have a control that suggests a set of values in a drop-down list but also allows a user to type in their own value.
Method
[edit | edit source]Just add the attribute selection="open" to your select1 control:
<xf:select1 ref="my-data" selection="open">
Screen Image
[edit | edit source]Note that although a list of possible countries is listed, the user can type in any country that is not on this list.
XForms Application
[edit | edit source]The following example allows you to select a country code or enter your own country code:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>XForms Select1 Control Using Open Selection</title>
<style type="text/css"><![CDATA[body {font-family: Helvetica, sans-serif;}]]></style>
<xf:model>
<xf:instance xmlns="">
<data>
<CountryCode/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>XForms Select1 control using selection="open"</p>
<xf:select1 ref="CountryCode" selection="open">
<xf:label>Country:</xf:label>
<xf:item>
<xf:label>USA</xf:label>
<xf:value>usa</xf:value>
</xf:item>
<xf:item>
<xf:label>Canada</xf:label>
<xf:value>can</xf:value>
</xf:item>
<xf:item>
<xf:label>Japan</xf:label>
<xf:value>jpn</xf:value>
</xf:item>
<xf:item>
<xf:label>Mexico</xf:label>
<xf:value>mex</xf:value>
</xf:item>
<xf:item>
<xf:label>Other</xf:label>
<xf:value>other</xf:value>
</xf:item>
</xf:select1>
<br/>
Output: <xf:output ref="CountryCode"/>
</body>
</html>
Discussion
[edit | edit source]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".
Select
XForms Checkbox Buttons
[edit | edit source]There is just a small difference between using xf:select1 for radio buttons and the xf:select for multiple selection check boxes. In this example instead of round circles there are squares and you can check multiple squares. Note that the output contains a string with spaces between the values. This is why screen labels can have spaces but values should only contain dashes between the values.
Note that in this program we use appearance="full" attribute.
Screen Image
[edit | edit source]XForms Application
[edit | edit source]Note that as you select multiple items a space-delimited list of items appears in the output. This is a good example of why you do not want to put any spaces in a selection item value tag.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
>
<head>
<title>XForms Radio Button Using xf:Select appearance="full"</title>
<xf:model>
<xf:instance xmlns="">
<data>
<MyCode type="xs:string"/>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<p>XForms Radio Button Using Select appearance="full"</p>
<xf:select ref="MyCode" selection="closed" appearance="full" >
<xf:item>
<xf:label>Red</xf:label>
<xf:value>red</xf:value>
</xf:item>
<xf:item>
<xf:label>Orange</xf:label>
<xf:value>orange</xf:value>
</xf:item>
<xf:item>
<xf:label>Yellow</xf:label>
<xf:value>yellow</xf:value>
</xf:item>
<xf:item>
<xf:label>Green</xf:label>
<xf:value>green</xf:value>
</xf:item>
<xf:item>
<xf:label>Blue</xf:label>
<xf:value>blue</xf:value>
</xf:item>
</xf:select>
Output: <xf:output ref="/data/MyCode"/>
</body>
</html>
Using the Appearance Attribute
[edit | edit source]There are many ways to change the amount of screen area used to display a selection list with many items. The XForms specification suggests that the user can control this area using a simple attribute called appearance. The three suggested values of appearance are:
appearance="full" appearance="compact" appearance="minimal"
Where:
"full": all choices should be rendered at all times. "compact": a fixed number of choices should be rendered, with scrolling facilities as needed "minimal": a minimum number of choices should be rendered, with a facility to temporarily render additional choices
Many systems simply use a CSS style sheet to change this layout.
W3C Specification on the User Interface Options for Selecting Many
Testing
[edit | edit source]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.
Select Multi-Column
Motivation
[edit | edit source]Sometimes you have a large number of items to select from, for example you want to include one of many counties within a state to include in your search. In the following example there are 87 counties that might be included in a search. These county names are places in seven columns with 13 counties in all but the last column.
Screen Image
[edit | edit source]Link to Working Example
[edit | edit source]Sample Program
[edit | edit source]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() < 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() > 13) and (position() < 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() > 26) and (position() < 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() > 39) and (position() < 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() > 52) and (position() < 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() > 65) and (position() < 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() > 78)]">
<xf:label ref="Label" />
<xf:value ref="Value" />
</xf:itemset>
</xf:select>
</div>
</div>
<xf:output ref="counties">
<xf:label>Counties selected: </xf:label>
</xf:output>
</body>
</html>
Table for Data
[edit | edit source]The following is the shared resources file used by all the forms. Note that the values do not have any spaces in them. This way the codes can be passed through systems that use spaces as delimineters.
<CodeTable>
<DataElementName>MNCountyCode</DataElementName>
<EnumeratedValues>
<Item>
<Label>Aitkin</Label>
<Value>aitkin</Value>
</Item>
<Item>
<Label>Anoka</Label>
<Value>anoka</Value>
</Item>
<Item>
<Label>Becker</Label>
<Value>becker</Value>
</Item>
<Item>
<Label>Beltrami</Label>
<Value>beltrami</Value>
</Item>
<Item>
<Label>Benton</Label>
<Value>benton</Value>
</Item>
<Item>
<Label>Big Stone</Label>
<Value>big-stone</Value>
</Item>
<Item>
<Label>Blue Earth</Label>
<Value>blue-earth</Value>
</Item>
<Item>
<Label>Brown</Label>
<Value>brown</Value>
</Item>
<Item>
<Label>Carlton</Label>
<Value>carlton</Value>
</Item>
<Item>
<Label>Carver</Label>
<Value>carver</Value>
</Item>
<Item>
<Label>Cass</Label>
<Value>cass</Value>
</Item>
<Item>
<Label>Chippewa</Label>
<Value>chippewa</Value>
</Item>
<Item>
<Label>Chisago</Label>
<Value>chisago</Value>
</Item>
<Item>
<Label>Clay</Label>
<Value>clay</Value>
</Item>
<Item>
<Label>Clearwater</Label>
<Value>clearwater</Value>
</Item>
<Item>
<Label>Cook</Label>
<Value>cook</Value>
</Item>
<Item>
<Label>Cottonwood</Label>
<Value>cottonwood</Value>
</Item>
<Item>
<Label>Crow Wing</Label>
<Value>crow-wing</Value>
</Item>
<Item>
<Label>Dakota</Label>
<Value>dakota</Value>
</Item>
<Item>
<Label>Dodge</Label>
<Value>dodge</Value>
</Item>
<Item>
<Label>Douglas</Label>
<Value>douglas</Value>
</Item>
<Item>
<Label>Faribault</Label>
<Value>faribault</Value>
</Item>
<Item>
<Label>Fillmore</Label>
<Value>fillmore</Value>
</Item>
<Item>
<Label>Freeborn</Label>
<Value>freeborn</Value>
</Item>
<Item>
<Label>Goodhue</Label>
<Value>goodhue</Value>
</Item>
<Item>
<Label>Grant</Label>
<Value>grant</Value>
</Item>
<Item>
<Label>Hennepin</Label>
<Value>hennepin</Value>
</Item>
<Item>
<Label>Houston</Label>
<Value>houston</Value>
</Item>
<Item>
<Label>Hubbard</Label>
<Value>hubbard</Value>
</Item>
<Item>
<Label>Isanti</Label>
<Value>isanti</Value>
</Item>
<Item>
<Label>Itasca</Label>
<Value>itasca</Value>
</Item>
<Item>
<Label>Jackson</Label>
<Value>jackson</Value>
</Item>
<Item>
<Label>Kanabec</Label>
<Value>kanabec</Value>
</Item>
<Item>
<Label>Kandiyohi</Label>
<Value>kandiyohi</Value>
</Item>
<Item>
<Label>Kittson</Label>
<Value>kittson</Value>
</Item>
<Item>
<Label>Koochiching</Label>
<Value>koochiching</Value>
</Item>
<Item>
<Label>Lac Qui Parle</Label>
<Value>lac-qui-parle</Value>
</Item>
<Item>
<Label>Lake</Label>
<Value>lake</Value>
</Item>
<Item>
<Label>Lake of the Woods</Label>
<Value>lake-of-the-woods</Value>
</Item>
<Item>
<Label>Lesueur</Label>
<Value>lesueur</Value>
</Item>
<Item>
<Label>Lincoln</Label>
<Value>lincoln</Value>
</Item>
<Item>
<Label>Lyon</Label>
<Value>lyon</Value>
</Item>
<Item>
<Label>Mahnomen</Label>
<Value>mahnomen</Value>
</Item>
<Item>
<Label>Marshall</Label>
<Value>marshall</Value>
</Item>
<Item>
<Label>Martin</Label>
<Value>martin</Value>
</Item>
<Item>
<Label>McLeod</Label>
<Value>mcleod</Value>
</Item>
<Item>
<Label>Meeker</Label>
<Value>meeker</Value>
</Item>
<Item>
<Label>Mille Lacs</Label>
<Value>mille-lacs</Value>
</Item>
<Item>
<Label>Morrison</Label>
<Value>morrison</Value>
</Item>
<Item>
<Label>Mower</Label>
<Value>mower</Value>
</Item>
<Item>
<Label>Murray</Label>
<Value>murray</Value>
</Item>
<Item>
<Label>Nicollet</Label>
<Value>nicollet</Value>
</Item>
<Item>
<Label>Nobles</Label>
<Value>nobles</Value>
</Item>
<Item>
<Label>Norman</Label>
<Value>norman</Value>
</Item>
<Item>
<Label>Olmsted</Label>
<Value>olmsted</Value>
</Item>
<Item>
<Label>Otter Tail</Label>
<Value>otter-tail</Value>
</Item>
<Item>
<Label>Pennington</Label>
<Value>pennington</Value>
</Item>
<Item>
<Label>Pine</Label>
<Value>pine</Value>
</Item>
<Item>
<Label>Pipestone</Label>
<Value>pipestone</Value>
</Item>
<Item>
<Label>Polk</Label>
<Value>polk</Value>
</Item>
<Item>
<Label>Pope</Label>
<Value>pope</Value>
</Item>
<Item>
<Label>Ramsey</Label>
<Value>ramsey</Value>
</Item>
<Item>
<Label>Red Lake</Label>
<Value>red-lake</Value>
</Item>
<Item>
<Label>Redwood</Label>
<Value>redwood</Value>
</Item>
<Item>
<Label>Renville</Label>
<Value>renville</Value>
</Item>
<Item>
<Label>Rice</Label>
<Value>rice</Value>
</Item>
<Item>
<Label>Rock</Label>
<Value>rock</Value>
</Item>
<Item>
<Label>Roseau</Label>
<Value>roseau</Value>
</Item>
<Item>
<Label>Saint Louis</Label>
<Value>saint-louis</Value>
</Item>
<Item>
<Label>Scott</Label>
<Value>scott</Value>
</Item>
<Item>
<Label>Sherburne</Label>
<Value>sherburne</Value>
</Item>
<Item>
<Label>Sibley</Label>
<Value>sibley</Value>
</Item>
<Item>
<Label>Stearns</Label>
<Value>stearns</Value>
</Item>
<Item>
<Label>Steele</Label>
<Value>steele</Value>
</Item>
<Item>
<Label>Stevens</Label>
<Value>stevens</Value>
</Item>
<Item>
<Label>Swift</Label>
<Value>swift</Value>
</Item>
<Item>
<Label>Todd</Label>
<Value>todd</Value>
</Item>
<Item>
<Label>Traverse</Label>
<Value>traverse</Value>
</Item>
<Item>
<Label>Wabasha</Label>
<Value>wabasha</Value>
</Item>
<Item>
<Label>Wadena</Label>
<Value>wadena</Value>
</Item>
<Item>
<Label>Waseca</Label>
<Value>waseca</Value>
</Item>
<Item>
<Label>Washington</Label>
<Value>washington</Value>
</Item>
<Item>
<Label>Watonwan</Label>
<Value>watonwan</Value>
</Item>
<Item>
<Label>Wilkin</Label>
<Value>wilkin</Value>
</Item>
<Item>
<Label>Winona</Label>
<Value>winona</Value>
</Item>
<Item>
<Label>Wright</Label>
<Value>wright</Value>
</Item>
<Item>
<Label>Yellow Medicine</Label>
<Value>yellow-medicine</Value>
</Item>
</EnumeratedValues>
</CodeTable>
Discussion
[edit | edit source]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.
Select1 Multi-Column
Motivation
[edit | edit source]You want to select one item from multiple column of items.
Method
[edit | edit source]To do this we must unselect all of the column not selected so that only one column has a value in the output.
Source Code
[edit | edit source]<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>Column 1: </xf:label>
</xf:output>
<br/>
<xf:output ref="col-2">
<xf:label>Column 2: </xf:label>
</xf:output>
<br/>
<xf:output ref="col-3">
<xf:label>Column 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>
Selecting from Model
Motivation
[edit | edit source]You want to store lists in the model, not in the user interface. This allows a list to be used many places in a form and also enables lists to be read from external files (see the next example).
Screen Image
[edit | edit source]Execute Sample XForms Application
[edit | edit source]Sample Program
[edit | edit source]This example shows how to use the XForms itemset
element to get data from the selection list directly from the model. Note that itemset is very similar to the group command in syntax: the outer loop tells you where to get your data and the inner loop binds a data element to a form value or item.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Getting Selection List Data From the XForms Model</title>
<style type="text/css"><![CDATA[
body {font-family: Helvetica, Verdanan, sans-serif;}
]]>
</style>
<xf:model>
<!-- this instance holds the data you send to the server on save -->
<xf:instance id="my-item" xmlns="">
<data>
<!-- the default color is red -->
<ItemColorCode>red</ItemColorCode>
</data>
</xf:instance>
<!-- this instance holds the code tables used for all selection lists -->
<xf:instance id="code-tables" xmlns="">
<code-tables>
<code-table>
<code-table-id>ItemColorCode</code-table-id>
<item>
<label>Red</label>
<value>red</value>
</item>
<item>
<label>Orange</label>
<value>orange</value>
</item>
<item>
<label>Yellow</label>
<value>yellow</value>
</item>
<item>
<label>Green</label>
<value>green</value>
</item>
<item>
<label>Blue</label>
<value>blue</value>
</item>
</code-table>
</code-tables>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Getting Selection List Data From the XForms Model</h1>
<xf:select ref="ItemColorCode" appearance="full">
<xf:itemset
nodeset="instance('code-tables')/code-table[code-table-id='ItemColorCode']/item">
<xf:label ref="label"/>
<xf:value ref="value"/>
</xf:itemset>
</xf:select>
<br/> Output: <xf:output ref="ItemColorCode"/>
</body>
</html>
Discussion
[edit | edit source]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.
Selecting Codes From File
Motivation
[edit | edit source]People who design forms frequently have to maintain many code tables. These code tables may change frequently and there may be processes that update a database of centrally maintained code tables. So you want each form to dynamically get the current relevant codes from an XML file or a RESTful web service.
This sample program demonstrates how to read a list of codes with labels directly from a file or code-table web service. In this example the file that contains the codes is just a well-formed XML file in the same directory that the form is located in.
Loading XML instance data from a local file or web service
[edit | edit source]The following code fragment, usually in the HTML head, demonstrates how to read XML data from a local file in the same directory as the form by using the "src" attribute of the instance.
Loading a Single Codes Table into a Single Instance
[edit | edit source]<html>
<xf:model>
<xf:instance src="XMLSchemaTypeCode.xml" id="XMLSchemaTypeCode"/>
</xf:model>
</html>
Loading Codes from a Web Service
[edit | edit source]It is common to have a single web service load all code tables. This service can be passed parameters such as the name of the code table as well as the group the person is a part of. This can narrow down the list of selections for long lists.
<html>
<xf:model>
<xf:instance id="ApprovalCodes" src="/db/mdr/services/all-codes.xq?code=ApprovalCodes&group=editor"/>
</xf:model>
</html>
Loading all Codes into a single Instance
[edit | edit source]The problem with loading individual code tables into individual instances is that you must perform a separate HTTP get for each code table. This is not a problem for forms with one or two small selection lists. But for large forms with many selection lists this can slow down form response time. The solution is to load all codes into a single instance with a single HTTP GET request. Each code table can then be selected from this instance.
<html>
<xf:model>
<xf:instance id="code-tables" src="/db/mdr/services/all-codes.xq?form=DataElementManager&group=admin"/>
</xf:model>
</html>
In this second example all the codes in the entire form are generated by a service of the Metadata Registry (MDR). The data returned by this server is a collection of codes for each select1 control in the form.
This will look for a well-formed XML file in the current directory and load it into the model instance.
Note that in this case the model is given an id. This is necessary to allow multiple code tables to each be read into their own separate model.
Screen Image
[edit | edit source]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.
Note that label on the screen is not the same as the label stored in the model.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms" >
<head>
<title>Select List From File</title>
/* the default model */
<xf:model>
<xf:instance id="save-data" xmlns="">
<data>
<MyXMLSchemaTypeCode/>
</data>
</xf:instance>
<xf:instance id="code-tables" src="XMLSchemaTypeCode.xml"/>
</xf:model>
</head>
<body>
<p>This selection list was read from a file.</p>
<xf:select1 ref="/MyData/MyXMLSchemaTypeCode">
<xf:label>Select XML Schema data type: </xf:label>
<xf:itemset ref="instance('code-tables')/XMLSchemaTypeCode/item">
<xf:label ref="label"/>
<xf:value ref="value"/>
</xf:itemset>
</xf:select1>
<br/>
<xf:output ref="instance('save-data')/MyXMLSchemaTypeCode">
<xf:label>Value of MyXMLSchemaTypeCode: </xf:label>
</xf:output>
</body>
</html>
Sample XML Data
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<XMLSchemaTypeCode>
<label>XML Schema Type:</label>
<item>
<label>Date and Time</label>
<value>dateTime</value>
</item>
<item>
<label>Time (HH:MM:SS-06:00)</label>
<value>time</value>
</item>
<item>
<label>Date (yyyy-mm-dd)</label>
<value>date</value>
</item>
<item>
<label>Year and Month</label>
<value>gYearMonth</value>
</item>
<item>
<label>Year (nnnn)</label>
<value>gYear</value>
</item>
<item>
<label>Month and Day</label>
<value>gMonthDay</value>
</item>
<item>
<label>Day of Month (1 .. 31)</label>
<value>gDay</value>
</item>
<item>
<label>Month (1 .. 12)</label>
<value>gMonth</value>
</item>
<item>
<label>String</label>
<value>string</value>
</item>
<item>
<label>Boolean (true/false)</label>
<value>boolean</value>
</item>
<item>
<label>Base 64 Binary</label>
<value>base64Binary</value>
</item>
<item>
<label>Decimal (0.00)</label>
<value>decimal</value>
</item>
<item>
<label>Any URI</label>
<value>anyURI</value>
</item>
<item>
<label>Integer (...,-2,-1,0,1,2,...)</label>
<value>integer</value>
</item>
<item>
<label>Non-Positive Integer (...,-2,-1,0)</label>
<value>nonPositiveInteger</value>
</item>
<item>
<label>Negative Integer (...,-2,-1)</label>
<value>negativeInteger</value>
</item>
<item>
<label>Long (-9,223,372T .. 9,223,372T)</label>
<value>long</value>
</item>
<item>
<label>Int (-2,147,483,648 .. 2,147,483,647)</label>
<value>int</value>
</item>
<item>
<label>Short (-32,768 .. 32,767)</label>
<value>short</value>
</item>
<item>
<label>Byte (-128 .. 127)</label>
<value>byte</value>
</item>
<item>
<label>Non-negative Integer (0..N)</label>
<value>nonNegativeInteger</value>
</item>
<item>
<label>Positive Integer (1..N)</label>
<value>positiveInteger</value>
</item>
<item>
<label>Unsigned Long (0 .. 18,446,744T)</label>
<value>unsignedLong</value>
</item>
<item>
<label>Unsigned Int (0 .. 4,294,967,295)</label>
<value>unsignedInt</value>
</item>
<item>
<label>Unsigned Short (0.. 65,535)</label>
<value>unsignedShort</value>
</item>
<item>
<label>Unsigned Byte (0..255)</label>
<value>unsignedByte</value>
</item>
</XMLSchemaTypeCode>
Note that to be well-formed the XML file MUST contain a root data element that must match the node-set argument.
Extracting data from an XML REST web service
[edit | edit source]You can replace the instance src attribute with a path directly to a XML REST web service. For example, if you put all your code tables into a project resources collection the path would look like the following:
<xf:instance src="../resources/code-tables/PersonGenderCode.xml"/>
or if your system codes are stored in a single XML file and you have a wrapper XQuery
<xf:instance src="../resources/code-tables/get-codes-for.xq?element=PersonGenderCode"/>
Selection Lists From A Single Instance
[edit | edit source]To keep your forms fast, it is usually better to do a single HTTP GET operation for all your codes. Forms that have many selection lists will take a long time to load if each list does a separate HTTP GET operation. For large forms it is easy to get a 10x speedup in form load times.
Structure of Code Tables Instance
[edit | edit source]The following is a sample structure of all codes loaded into a single instance:
<xf:instance id="code-tables">
<code-tables>
<code-table>
<code-table-name>MyElementCode</code-table-name>
<items>
<item>
<label>Joe Smith</label>
<value>42</value>
</item>
<item>
<label>Sue Johnson</label>
<value>47</value>
</item>
<items>
</code-table>
<code-table>
<code-table-name>ColorCode</code-table-name>
<items>
<item>
<label>Red</label>
<value>1</value>
</item>
<item>
<label>Orange</label>
<value>2</value>
</item>
<items>
</code-table>
</code-tables>
</xf:instance>
Sample Select1
[edit | edit source]Once your data is loaded into your model, each of your select1 or select controls can get its data directly from the model using the xf:itemset element. Itemset works just like repeat and uses nodeset (not ref) to get all its values. Here is an example of how to get the itemset data from your code-tables instance.
<xf:select1 ref="instance('save-data')/MyElementName">
<xf:label>My Element:</xf:label>
<xf:itemset nodeset="instance('code-tables')/code-table[code-table-name='MyElementCode']/items/item">
<xf:label ref="label"/>
<xf:value ref="value"/>
</xf:itemset>
</xf:select1>
Note that the predicate [code-table-name='MyElementCode'] will only put the items for that code into the selection list.
Auto Generation of Code Tables from Metadata Registry
[edit | edit source]Because XML Schema does not contain information for presentation we use the following workflow as a "best practice".
- Store all label/value pairs in external code table files or get this information from a web service.
- For each form, create a web service that will generate a code-tables element for all the codes used in that form.
- Load the code-tables element into a separate instance in your model with an id of "code-tables".
- Select the code table out of that instance for each select1 or select element by getting a code table with that name.
Discussion
[edit | edit source]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.
Selecting a Date
Motivation
[edit | edit source]Users frequently want to select a date rather than have to type the date into a field. They often want to select a date such as "next Tuesday", but they might have to use a calendar to look up the day that Tuesday falls on.
Luckily a calendar selector is built in to most XForms implementations.
Screen Image
[edit | edit source]If you have a field that is "bound" to a date type the form will appear as follows:
Link to Working XForms Application
[edit | edit source]Sample Program
[edit | edit source]Here is an example that uses the date picker:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Example using a date selector by binding an instance to an XML Schema date type</title>
<xf:model>
<xf:instance xmlns="">
<data>
<MyDate />
</data>
</xf:instance>
<xf:bind nodeset="MyDate" type="xs:date" />
</xf:model>
</head>
<body>
<p>Example of using the date selector by binding an instance to an XML Schema date type:
<br />
<xf:input ref="MyDate">
<xf:label>Enter a date: </xf:label>
</xf:input>
</p>
</body>
</html>
Testing
[edit | edit source]A small calendar icon should appear directly to the right of the input field. Click on the calendar icon and select a date. Note that you can change the day and the month using the calendar picker.
Discussion
[edit | edit source]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;
}
Formatting a date
Motivation
[edit | edit source]XML stores dates in the format YYYY-MM-DD such as 2007-08-30. Unfortunately this is usually not the way users want to view their dates.
This example XForms program uses CSS to hide an input date and an XPath expression to get the date to display in the MM/DD/YYYY format typically used in the US.
Screen Image
[edit | edit source]Link to XForm Example
[edit | edit source]Link to Date Format External Example
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:d="http://www.mydata.com/xmlns/data">
<head>
<title>Demo of date formatting using XPath concat and substring.</title>
<style type="text/css"><![CDATA[
@namespace xf url('http://www.w3.org/2002/xforms');
.hidden .xf-value {
display:none;
}
]]>
</style>
<xf:model>
<xf:instance xmlns="">
<MyModel>
<MyDate>2006-09-12</MyDate>
</MyModel>
</xf:instance>
<xf:bind nodeset="/MyModel/MyDate" type="xs:date" />
</xf:model>
</head>
<body>
<xf:input class="hidden" ref="/MyModel/MyDate" incremental="true">
<xf:label>Select Date: </xf:label>
</xf:input>
<!-- get the month (two characters wide starting at character number 6), then the day then the year -->
<xf:output
value="concat(substring(/MyModel/MyDate,6,2),
'/',
substring(/MyModel/MyDate,9,2),
'/',
substring(/MyModel/MyDate,1,4))"
/>
</body>
</html>
Discussion
[edit | edit source]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.
- The first substring goes to the 6th character and pulls out the two month (MM) characters.
- The second substring starts at the 9th character and gets two day (DD) characters.
- 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.
Upload
Motivation
[edit | edit source]The upload element allows you to select a file from the file system using your operating system's "Browse" user interface. This file can then be transferred to the file server that the web form resides.
Screen Image
[edit | edit source]Here is a screen image of the Firefox XForms extension upload control after the C:\tmp\Foo.xml file was selected:
The XForms upload
Element
[edit | edit source]<xf:upload ref="XPathExpression" mediatype="text/xml">
<xf:filename ref="XPathExpression" />
<xf:mediatype ref="XPathExpression" />
</xf:upload>
Sample Program
[edit | edit source]This sample program has a single instance variable called "File". At the end of the select this variable is set to the path-name of the file you just selected.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<head>
<title/>
<xf:model>
<xf:instance xmlns="">
<Data>
<File xsi:type="xs:anyURI"/>
</Data>
</xf:instance>
</xf:model>
</head>
<body>
<xf:upload ref="/Data/File">
<xf:filename>file:///C:/tmp/*.xml</xf:filename>
<xf:mediatype>text/xml</xf:mediatype>
</xf:upload>
<br/>
<xf:output ref="/Data/File">
<xf:label>File: </xf:label>
</xf:output>
</body>
</html>
Discussion
[edit | edit source]At the time of this writing, there is little documentation on how the upload control works. The screen shot above was taken from the Firefox XForms 0.8 running on Firefox 3 implementation. Note that the file name appears twice in the control itself. This may not be the future behavior. This may be that the filename and mediatype text inside the control are being displayed. There is no documentation yet on how to disable the clear trigger.
There is not yet documentation on how to upload instance data into the model using the upload control. Right now instance data must be hard-coded into the src
attribute of an instance.
The following loads both an image and a URI.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<head>
<title/>
<xf:model>
<xf:instance xmlns="">
<data>
<image xsi:type="xs:base64Binary"/>
<uri xsi:type="xs:anyURI"/>
</data>
</xf:instance>
<xf:submission id="save" action="http://xformstest.org/cgi-bin/showinstance.sh" method="post"/>
</xf:model>
</head>
<body>
<xf:upload ref="image">
<xf:label>Upload Photo:</xf:label>
</xf:upload>
<br/>
<xf:upload ref="uri">
<xf:label>Upload File:</xf:label>
<xf:filename>file:///C:/tmp/*.xml</xf:filename>
<xf:mediatype>text/xml</xf:mediatype>
</xf:upload>
<br/>
<xf:output ref="image">
<xf:label>image: </xf:label>
</xf:output>
<br/>
<xf:output ref="uri">
<xf:label>uri: </xf:label>
</xf:output>
<br/>
<xf:submit submission="save">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
Uploading Binary Files
[edit | edit source]Any file type such as an image or XML file can be converted to a 64bit encoded file, stored in the instance and then transmitted to the server inside of a POST. On the server the file can be converted back to a string or binary.
Sample Echo With Binary to String Unencoding
[edit | edit source]The following is a simple echo script written in XQuery that echos back the binary file in XML. It is an XQuery script that uses a binary-to-string conversion function. This takes a file of type xs:base64binary and returns a string representation of the file. The data to be returned is in the element with the element name "xml-base64".
xquery version "1.0";
declare option exist:serialize "method=xml media-type=text/xml indent=yes";
(: this gets the data from the HTTP POST :)
let $post-data := request:get-data()
(: this converts the base-64 binary to a plaintext string that holds the unparsed XML content :)
let $xml-as-string := util:base64-decode($post-data//xml-base64)
let $parsed-xml := util:parse($xml-as-string)
return
<results>
<xml-as-string>{$xml-as-string}</xml-as-string>
<parsed-xml>{$parsed-xml}</parsed-xml>
</results>
Sample Form
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<head>
<title>Upload XML</title>
<xf:model>
<xf:instance xmlns=''>
<data>
<xml-base64 xsi:type="xs:base64Binary"/>
</data>
</xf:instance>
<xf:submission id='post-to-echo'
action='echo-base64-binary.xq' replace="all"
method='post'/>
</xf:model>
</head>
<body>
<br/>
<xf:upload ref="xml-base64">
<xf:label>Upload XML File:</xf:label>
</xf:upload>
<br/>
<xf:output ref="xml-base64">
<xf:label>XML file encoded in base64binary: </xf:label>
</xf:output>
<br/>
<xf:submit submission="post-to-echo">
<xf:label>Post to Echo</xf:label>
</xf:submit>
</body>
</html>
Sample File
[edit | edit source]<test>This is a small XML file.</test>
Warnings
[edit | edit source]The attribute data type assignment xsi:type="xs:anyURI"
must be associated with the variable used to store the file path name.
References
[edit | edit source]
Trigger
Motivation
[edit | edit source]XForms creates a general way to represent a button that will work on web pages and cell phones. But it is not called "button" as in most other systems. It is an abstraction or generalization of a button called a trigger
. A trigger is an abstraction of a web button or another event such as a button on a cell phone. Using a trigger abstraction allows your XForms to be more portable.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
>
<head>
<title>Button Example</title>
<xf:model>
<xf:instance xmlns="">
<data/>
</xf:instance>
</xf:model>
</head>
<body>
<xf:trigger>
<xf:label>Button</xf:label>
<xf:hint>If you press this you will get a hello world message.</xf:hint>
<xf:message level="modal" ev:event="DOMActivate">Hello World!</xf:message>
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]This example has both a label and a hint. XForms also has help text that can be used but the way help is implemented is implementation specific.
Styling a Trigger
[edit | edit source]By default each trigger looks like an HTML button. You can turn this off by setting appearance="minimal".
<xf:trigger appearance="minimal">
<xf:label>Save</xf:label>
</xf:trigger>
Having a Button Trigger Multiple Events
[edit | edit source]When you press on a button (trigger) you sometimes want the trigger to do more than a single submission. Whenever you want to do this you can just add an action element and wrap multiple sends in the action:
<xf:trigger>
<xf:label>Submit</xf:label>
<xf:action ev:event="DOMActivate">
<xf:send submission="getTime"/>
<xf:send submission="getTemperature"/>
</xf:action>
</xf:trigger>
References
[edit | edit source]
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: .
Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>XForms Trigger Appearances</title>
<xf:model>
<xf:instance xmlns="">
<data>
<label>Label text from the model</label>
<message>Message text from the model</message>
<hint>Hint text from the model</hint>
</data>
</xf:instance>
<xf:submission method="post" id="submission" />
</xf:model>
</head>
<body>
<h1>Test of Trigger Appearances</h1>
<p>A simple model button that brings up a message in a window:
<br/>
<xf:trigger>
<xf:label>Simple Button</xf:label>
<xf:message level="modal" ev:event="DOMActivate">Button clicked</xf:message>
</xf:trigger>
<br/>
</p>
<p>A model button that also displays "hint text" when you hover over the button:
<br />
<xf:trigger>
<xf:label>Button With Hint Text On Hover</xf:label>
<xf:message level="modal" ev:event="DOMActivate">Button clicked</xf:message>
<xf:hint>This is the hint text.</xf:hint>
</xf:trigger>
<br />
</p>
<p>A button that includes an image and hint text:
<br />
<xf:trigger appearance="xf:image">
<img src="XForms-button.jpg" />
<xf:message level="modal" ev:event="DOMActivate">Image
clicked</xf:message>
<xf:hint>This hint text comes up if you hover over a button.</xf:hint>
</xf:trigger>
<br />
</p>
<p>A button that includes text, and image and text:
<br />
<xf:trigger appearance="xf:image">
<xf:label>Text before the image... <img src="XForms-button.jpg" /> ...text after the image.</xf:label>
<xf:message level="modal" ref="message" ev:event="DOMActivate" />
<xf:hint>Hints work with labels and images.</xf:hint>
</xf:trigger>
<br />
</p>
<p>A trigger that extracts the label, hint and message text from the model:
<br />
<xf:trigger>
<xf:label ref="label" />
<xf:message level="modal" ref="message" ev:event="DOMActivate" />
<xf:hint ref="hint" />
</xf:trigger>
<br />
</p>
</body>
</html>
Discussion
[edit | edit source]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.
Range
NOTE
[edit | edit source]These examples do not appear to work with the FireFox 3 XForms addition. Sliders are hidden with XSLTForms (r406).
Motivation
[edit | edit source]You want to use a range control or "slider" to set a numeric value in your form.
Selecting from a continuous range of values
[edit | edit source]The range is a control that is part of the XForms specification. It allows the user to select a numeric value from a range of values without using the keyboard. This is ideal for instructors that use interactive learning environments such as a SmartBoard.
The XForms range has four attributes:
- start - the lower bound of the range
- end - the upper bound of the range
- step - the increment of output change
- incremental - true if the form should send continuous values to the model or false otherwise. The default is false.
These attributes MUST be bound to an element that has a numeric datatype. To do this you must add the following bind statements to your model:
<xf:bind nodeset="/data/my-int" type="xs:integer"/>
<xf:bind nodeset="/data/my-decimal" type="xs:decimal"/>
User Interface
[edit | edit source]There are three range controls in this application. The value of the range is on the right side.
Link to XForms Application
[edit | edit source]Sample User Interface
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>XForms Submit Example</title>
<style type="text/css">
body {
font-family: Helvetica, sans-serif;
}
</style>
<xf:model>
<xf:instance xmlns="">
<data>
<data1>3.14159</data1>
<data2>6</data2>
<data3>66</data3>
</data>
</xf:instance>
<!-- you MUST bind each data type to the decimal type for the range control to work -->
<xf:bind nodeset="/data/data1" type="xs:decimal" />
<xf:bind nodeset="/data/data2" type="xs:decimal" />
<xf:bind nodeset="/data/data3" type="xs:decimal" />
</xf:model>
</head>
<body>
<xf:range ref="data1" start="1" end="5" step="1" incremental="true">
<xf:label>Data1: </xf:label>
</xf:range>
<xf:output ref="data1">
<xf:label> Value= </xf:label>
</xf:output>
<br />
<xf:range ref="data2" start="1" end="10" step="1" incremental="true">
<xf:label>Data2: </xf:label>
</xf:range>
<xf:output ref="data2">
<xf:label> Value= </xf:label>
</xf:output>
<br />
<xf:range ref="data3" start="1" end="100" step="5" incremental="true">
<xf:label>Data3: </xf:label>
</xf:range>
<xf:output ref="data3">
<xf:label> Value= </xf:label>
</xf:output>
</body>
</html>
Testing
[edit | edit source]Select one of the three range controls with the mouse. Drag the value to the right or left. You should notice that the values at the right also are updated.
The first control just selects decimals from 1 to 5. The second uses the step to return only integers. The last has a range of 1 to 100 in increments of 5. Note that the value is 66 and you cannot set a value from 62 to 65.
Discussion
[edit | edit source]The upper and lower values of the range control can also be set directly in the model. XML Schema provides a minValue and a maxValue that can be used to adjust the range control limits.
W3C Specification
[edit | edit source]Here is the specification from the W3C web site: W3C range specification
Send
Motivation
[edit | edit source]You want to send a request to a web server to add additional XML data into your form. This allows different parts of an XForms to defer getting data till it is needed. This makes large forms load faster and avoids unessary network traffic.
Using the send element
[edit | edit source]The send element has a single parameter which is submission. This must be the ID of one of the submission elements in your model.
Here is and example:
<xf:send submission="get-additional-data"/>
If you reference this submission you will need a corresponding submission in your model.
<xf:model>
<xf:submission id="get-additional-data" .../>
</xf:model>
Common Usage
[edit | edit source]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.
Load
Motivation
[edit | edit source]You want to load a new resource over your current form.
Usage
[edit | edit source]In HTML links are simple. You use the HTML anchor tag
<a href="http://example.com">like label</a></nowiki>
However, in XForms, it is a bit more complex:
<xf:trigger appearance="minimal">
<xf:label>Go to Google</xf:label>
<xf:action ev:event="DOMActivate">
<xf:load show="replace">
<xf:resource value="'http://www.google.com'"/>
</xf:load>
</xf:action>
</xf:trigger>
The XForms xf:load element has several attributes.
- ref - a static reference to a single node
- resource - a static URL such as a relative or absolute URL
- show - if a new page is created or the current page replaced. Show can have two values: new or replace.
- target - the target action to be executed
One is the URI of the resource to load and the other is the show attribute. The show attribute can have values of "replace" which will replace the current form with the new resource and "new" which will open a new tab in your web browser or a new window if you are running older browsers such as IE 6.
<xf:load resource="search.xq" show="new"/>
<xf:load resource="search.xq" show="replace"/>
xf:load can also be used to run a local javascript function when a form loads:
<xf:action ev:event="xforms-ready">
<xf:load resource="javascript:init()"/>
</xf:action>
Loading Dynamic Strings
[edit | edit source]Note that the ref attribute of xf:load can only be a static string. You can not change this as the XForms application changes.
If you need to load dynamic string the way to do this is to use the xf:resource element within the xf:load element. The xf:resource element has a value attribute that is used to hold all the dynamic expressions.
For example, the following example concats a URL and the search query from an input field.
<xf:load show="replace">
<xf:resource value="concat(url, q)"/>
</xf:load>
Load with resource attribute value templates
[edit | edit source]Some implementations allow you to dynamically create URLs based on data in our mode.
<xf:load ev:event= "DOMActivate"
resource= "http://www.google.com/{concat(string(instance('instance')/a), '{', '{{', string(instance('instance')/b), '}', '}}')}/{{something}}/else">
</xf:load>
Releated XForms Examples
[edit | edit source]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
Selecting Text
Motivation
[edit | edit source]You want to use a selection list to conditionally populate a text area.
<xf:model>
<xf:instance id="save-data">
<data xmlns="">
<message-type>test-message-1</message-type>
<current-message/>
</data>
</xf:instance>
<xf:instance id="code-table">
<data xmlns="">
<messages>
<message type="test-message-1">Message Type 1</message>
<message type="test-message-2">Message Type 2</message>
<message type="test-message-3">Message Type 3</message>
</messages>
</data>
</xf:instance>
<xf:bind nodeset="instance('save-data')/current-message"
calculate="instance('code-table')/messages/message[@type = instance('save-data')/message-type]"/>
<xf:submission id="post-test" method="post" action="echo-post.xq"
instance="save-data" replace="all"/>
</xf:model>
<body>
<p>Enter a message in the text area below and press the "Submit via HTTP POST" button.</p>
<div class="block-form">
{$style}
<xf:select1 ref="message-type" class="message">
<xf:label>Message Type:</xf:label>
<xf:item>
<xf:label>Test Message 1</xf:label>
<xf:value>test-message-1</xf:value>
</xf:item>
<xf:item>
<xf:label>Test Message 2</xf:label>
<xf:value>test-message-2</xf:value>
</xf:item>
<xf:item>
<xf:label>Test Message 3</xf:label>
<xf:value>test-message-3</xf:value>
</xf:item>
</xf:select1>
<xf:textarea ref="current-message">
<xf:label>Message:</xf:label>
</xf:textarea>
</div>
<xf:submit submission="post-test">
<xf:label>Submit via HTTP POST</xf:label>
</xf:submit>
</body>
Validation with Bind
Motivation
[edit | edit source]You want to validate a single field based on a rule and alert the user if they enter an invalid value.
Method
[edit | edit source]We will use an XForms bind expression:
<xf:bind nodeset="PositiveDecimalAmount" type="xs:decimal" constraint=". > 0"/>
This last line says that if the current element is greater than zero then the rule passes and the field is valid.
Screen Image
[edit | edit source]Sample Code
[edit | edit source] <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=". > 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=". < 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>
Case Validation
Motivation
[edit | edit source]You want to check to see if a field is upper or lower case.
Note: This does not seem to work in FireFox or XSLTForms.
Method
[edit | edit source]We will use a bind constraint.
<xf:bind nodeset="UpperCaseText" type="xs:string" constraint=" . eq translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') "/>
Sample Source Code
[edit | edit source]<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>
Limiting Length
Motivation
[edit | edit source]You want to warn a user that an input control exceeds a specified length.
Method
[edit | edit source]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(.) > 50">
<xf:message level="modal">maximum length is 50 characters</xf:message>
</xf:action>
Example with Textarea
[edit | edit source]<xf:textarea ref="short-message" incremental="true">
<xf:label>Message:</xf:label>
<xf:action ev:event="xforms-value-changed" if="string-length(.) > 140">
<xf:message level="modal">Maximum message length is 140 characters.</xf:message>
</xf:action>
</xf:textarea>
<xf:output ref="short-message"/>
Server-Side Field Validation
Motivation
[edit | edit source]Steps
[edit | edit source]Step 1: Add instances for outgoing and incoming data
[edit | edit source]<!-- store the outgoing data for the invalid e-mail check -->
<xf:instance id="email-out">
<data xmlns="">
<email></email>
</data>
</xf:instance>
<!-- place to store the results of an invalid e-mail check -->
<xf:instance id="email-check-results">
<data xmlns=""/>
</xf:instance>
Step 2: Add a submission element to the model
[edit | edit source]The submission element connects the "field changed" event to a service on the server.
<xf:submission id="email-check" method="get" action="email-check.xq"
ref="instance('email-check')"
replace="instance" instance="email-check-results" />
Step 3: Add an action to your input
[edit | edit source]<xf:input ref="email" >
<xf:label>Email: </xf:label>
<xf:hint>This field must contain a valid email format.</xf:hint>
<xf:action ev:event="xforms-value-changed">
<!-- copy from your "save-data" into the outgoing instance -->
<xf:setvalue ref="instance('email-out')/email" value="instance('save-data')/email"/>
<xf:send submission="email-check"/>
</xf:action>
</xf:input>
Step 4: Add a group that displays errors if the results are invalid
[edit | edit source]<xf:group ref="instance('email-check-results')/message[@class='error']">
<div class="field-warn"><xf:output value="instance('email-check-results')/message"/></div>
</xf:group>
Step 5: Create a server-side REST GET service that returns true/false
[edit | edit source]If there are no errors just return <ok/>
If there are errors return
<message type="error">Invalid e-mail format</message>
Submit
The Submit Element
[edit | edit source]One of the reasons that we have been careful to store all of our data in the model is that once this is done it makes it easy for a web client to simply serialize this model into XML and send it to a file, a web service, or possibly to a database.
This is all done by using a simple submit
command. submit is really just a trigger with an attribute of submission that points to a submission element in the model. This is usually a button with the word "Submit" or "Save" on it that appears at the end of the form.
On many HTML forms you fill out the form and press a button at the bottom of the form called "Save" or "Submit". You pressed the button and hoped your data would get saved. This is the same concept. But in this case the submit command can be triggered in many ways other that just a button being pressed and there are explicit ways of getting feedback from the receiver that the submission process succeeded.
The submit event behaves exactly like a trigger but with one key exception, the xforms-submit
event is also dispatched.
A model can have more than one submission identified by id
<xforms:submission id="s001" method="post" action="action.php"/>
<xforms:submission id="s002" method="post" action="action2.php" replace="instance"/>
<xforms:submission id="s003" method="put" action="file:///tmp/final.xml"/>
The first submission sends the data to the specified action, while the second one will expect to get a return xml to update the current document/instance. The third one will save the file locally to the given location /tmp/final.xml
Screen Image
[edit | edit source]The interface is very simple. It is just a simple "Save" button created by a trigger called submit.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>XForms Submit Example</title>
<xf:model>
<xf:instance xmlns="">
<MyData>
<Data1>One</Data1>
<Data2>Two</Data2>
<Data3>Three</Data3>
</MyData>
</xf:instance>
<xf:submission id="save" method="put" action="myData.xml" ref="/MyData"/>
</xf:model>
</head>
<body>
<xf:submit submission="save">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/20021/XMLSchema-instance">
<head>
<title>Submission with get and put</title>
<xf:model>
<xf:instance id="data_instance" src="data.xml" xmlns=""></xf:instance>
<xf:submission id="read-from-file" method="get" action="data.xml" replace="instance"
instance="data-instance"></xf:submission>
<xf:submission id="save-to-file" method="put" action="data.xml" replace="instance"
instance="data_instance"></xf:submission>
</xf:model>
</head>
<body>
<p>Demonstration of using XForms to get and put data to local file using the submission
element.</p>
<xf:input ref="Element1">
<xf:label>Element1:</xf:label>
</xf:input>
<br />
<xf:input ref="Element2">
<xf:label>Element2:</xf:label>
</xf:input>
<br />
<xf:input ref="Element3">
<xf:label>Element3:</xf:label>
<br />
</xf:input>
<xf:submit submission="read-from-file">
<xf:label>Reload</xf:label>
</xf:submit>
<xf:submit submission="save-to-file">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
Analysis
[edit | edit source]The save button is really just a trigger with the name of "submit" and an attribute called submission.
<xf:submit submission="save">
The attribute submission="save"
points to the ID of the submission element inside the model.
<xf:submission id="save" method="put" action="myData.xml" ref="/MyData"/>
Note that because we used a "relative file name" (relative to the directory that the form was in) it will save the data in the same directory location that the form was located.
Discussion
[edit | edit source]You can also use absolute path names but you must be careful about how you describe a letter drive since there are no standards for this.
The following format worked for a Microsoft Windows system using the FireFox browser:
<xf:submission id="save" method="put" action="file:/C:/tmp/myData.xml" ref="/MyData"/>
Web Server Configuration
[edit | edit source]Note: This section was written by a person that does not know much about web server administration. Read at your own risk and make sure a security professional reviews any changes to your public web servers.
Most of the examples in this tutorial are about learning XForms, not web server administration. That being said there are a few things we thought might be useful.
By default web servers are usually not configured to write files to your web server. Especially by un-authorized users. If this were the case hackers might use your web server to store their adult content.
To get XForms to save instance using "put", you should only allow writing to authorized users. To do this you will need to be able to administer your web server correctly.
Apache 2.2 Intranet Configuration with DAV
[edit | edit source]If you have a computer that is only accessible by internal users (usually called an Intranet) you can access, you can add the following to your Apache configuration file (usually called httpd.config and located in /usr/local/etc or similar location):
First, the following modules may have to be loaded:
mod_dav, mod_dav_fs, mod_dav_svn, mod_authz_svn.
This can be done by adding the following lines to your httpd.conf file:
LoadModule dav_module libexec/apache22/mod_dav.so LoadModule dav_fs_module libexec/apache22/mod_dav_fs.so
<Directory "usr/local/www/apache22/data/forms/read-write-test"> DAV on AllowOverride None Order allow,deny Allow from all </Directory>
By turning on DAV you will enable all of the WebDAV operations including "PUT".
IIS Configuration
[edit | edit source]To be done...
References
[edit | edit source]
Encoding Parameters
Motivation
[edit | edit source]When you submit data to a web service you want to change the way that parameters are encoded.
Method
[edit | edit source]Changing the Separator Character
[edit | edit source]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="&"
Note that the ampersand must be escaped.
(09 MAR 2009 the default was changed to ampersand in the official xsd-file)
Changing the URL encoding Parameter
[edit | edit source]You can also change the way that special characters are encoded by using the encoding attribute.
The options are any of the character encoding systems such as:
encoding="ISO-8859-1"
encoding="UTF-16"
Discussion
[edit | edit source]
Changing Namespaces in Submission
Motivation
[edit | edit source]You want to control the way that namespace prefixes are handled in your submission.
Method
[edit | edit source]We will use the includenamespaceprefixes attribute of a submission.
The XForms 1.1 specification allows the user to change the way that namespace prefixes are handled in a submitted element.
Here is an example of the use of the includenamespaceprefixes attribute to the submission element.
<xf:submission action="http://example.com/submit"
method="post" id="submit"
includenamespaceprefixes=""/>
<xf:submission action="http://example.com/submit"
method="post" includenamespaceprefixes="#default"/>
Sample Form
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:task="http://www.example.com/task"
task:dummy="dummy">
<head>
<title>Test of XForms Submission Namespace Inclusion</title>
<style type="text/css">
<![CDATA[
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Helvetica, sans-serif;}
.block-form xf|input { display: block; margin: 1ex; }
.block-form xf|label {display: inline-block; width: 15ex; float: left; text-align: right; margin-right: 1ex; font-weight: bold;}
]]>
</style>
<xf:model>
<xf:instance src="input-default-ns.xml" id='save-data'/>
<xf:submission id="submit-std"
action="http://localhost:8080/exist/rest/db/test/xforms/submission-tests/save-new.xq"
method="post"/>
<xf:submission id="submit-null"
action="http://localhost:8080/exist/rest/db/test/xforms/submission-tests/save-new.xq"
method="post"
includenamespaceprefixes=""/>
<xf:submission id="submit-default"
action="http://localhost:8080/exist/rest/db/test/xforms/submission-tests/save-new.xq"
method="post"
includenamespaceprefixes="#default"/>
</xf:model>
</head>
<body>
<h1>Submit Test</h1>
<div class="block-form">
<xf:input ref="instance('save-data')/task:id">
<xf:label>ID: </xf:label>
</xf:input>
<xf:input ref="task:task-name">
<xf:label>Name: </xf:label>
</xf:input>
<xf:input ref="task:task-description">
<xf:label>Description: </xf:label>
</xf:input>
</div>
<xf:submit submission="submit-std">
<xf:label>Without Attribute</xf:label>
</xf:submit>
<xf:submit submission="submit-null">
<xf:label>With Attribute Null</xf:label>
</xf:submit>
<xf:submit submission="submit-default">
<xf:label>With Default Namespace</xf:label>
</xf:submit>
</body>
</html>
Sample Instance Files
[edit | edit source]With Default Namespace
[edit | edit source]<task xmlns="http://www.example.com/task">
<task:id>123</task:id>
<task-name>Task Name</task-name>
<task-description>Task Description</task-description>
</task>
With Namespace Prefixes
[edit | edit source]<task:task xmlns:task="http://www.example.com/task">
<task:task:id>123</task:id>
<task:task-name>Task Name</task:task-name>
<task:task-description>Task Description</task:task-description>
</task:task>
Link to Working Example
[edit | edit source]Example Introduction to XForms 1.1 Submission Differences
Displaying Save Results
Motivation
[edit | edit source]After a save, you want to display a line at the end of your form to confirm that the results have been saved to the server. You also want to notify the user of any errors after a save.
Method
[edit | edit source]We will use the submission element to save the data and return the save results. We will use the <xf:group> to show either a success (in green) or a failure (in red).
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fr="http://orbeon.org/oxf/xml/form-runner" xmlns:xxforms="http://orbeon.org/oxf/xml/xforms" xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Save Test</title>
<xf:model>
<xf:instance xmlns="" id="save-data">
<formdata form-id="unit-tests-save-test">
<first-name>Dan</first-name>
<last-name>McCreary</last-name>
</formdata>
</xf:instance>
<xf:instance xmlns="" id="save-results">
<save-results>
<message>No Save Results Yet</message>
</save-results>
</xf:instance>
<xf:submission id="save-submission" ref="instance('save-data')"
method="post" resource="http://localhost:8088/exist/rest/db/apps/grants/scripts/save.xq"
replace="instance"
instance="save-results">
<xf:action ev:event="xforms-submit-done">
<xf:message>Save Done</xf:message>
</xf:action>
<xf:action ev:event="xforms-submit-error">
<xf:message>Save Failed</xf:message>
</xf:action>
</xf:submission>
<xf:submission id="save-submission-see-save-results" ref="instance('save-data')"
method="post" resource="http://localhost:8088/exist/rest/db/apps/grants/scripts/save.xq" replace="instance"
instance="save-results">
<xf:action ev:event="xforms-submit-done">
<xf:message>Save Done</xf:message>
</xf:action>
<xf:action ev:event="xforms-submit-error">
<xf:message>Save Failed</xf:message>
</xf:action>
</xf:submission>
</xf:model>
<style type="text/css">
.success {color: green; background-color: lightgreen;}
.failure {color: red; background-color: pink;}
</style>
</head>
<body>
<xf:input ref="first-name">
<xf:label>First name:</xf:label>
</xf:input>
<br/>
<xf:input ref="last-name">
<xf:label>Last name:</xf:label>
</xf:input>
<a href="http://localhost:8088/exist/rest/db/apps/xforms/scripts/save.xq">Save URL</a>
<div class="save-controls">
<xf:submit submission="save-submission" appearance="xxforms:primary" class="button-margin-top">
<xf:label>Save and Validate</xf:label>
</xf:submit>
<xf:submit submission="save-submission-see-save-results" class="button-margin-top">
<xf:label>Save See Save Results</xf:label>
</xf:submit>
</div>
<xf:group ref="instance('save-results')/.[@code='200']">
<div class="success">
<xf:output ref="instance('save-results')//message"/>
</div>
</xf:group>
<xf:group ref="instance('save-results')/.[@code='400']">
<div class="failure">
<xf:output ref="instance('save-results')//message"/>
</div>
</xf:group>
</body>
</html>
Sample XQuery
[edit | edit source]xquery version "1.0";
import module namespace config= "http://danmccreary.com/config" at "../modules/config.xqm";
declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare namespace xf="http://www.w3.org/2002/xforms";
declare namespace dc="http://gov/grantsolutions/dc";
let $log := util:log-system-out('running save.xq')
(: get-data() returns the document node. We want the root node :)
let $formdata := request:get-data()/*
(: check to make sure we have valid post data :)
return
if (not($formdata))
then <save-results code="400">No Post Data</save-results>
else
let $save-data-collection := concat($config:app-home-collection, '/save-data')
let $form-id :=
if (exists($formdata/@code))
then $formdata/@code/string()
else
if (exists($formdata/@form-id))
then $formdata/@form-id/string()
else 'unknown-form-id'
let $file-name := concat($form-id, '.xml')
let $path-name := concat($save-data-collection, '/', $file-name)
let $overwrite :=
if (doc-available($path-name))
then true()
else false()
let $store := xmldb:store($save-data-collection, $file-name, $formdata)
return
<save-results code="200">
{if ($overwrite)
then <message>Document updated at {$path-name}</message>
else <message>New document saved to {$path-name}</message>
}
</save-results>
Events Overview
Motivation
[edit | edit source]You want to be able to perform various tasks at various part of the form execution.
Method
[edit | edit source]XForms is integrated with the W3C XML Event standard. This standard creates standard names for almost all of the common events used in the lifecycle of a form. The W3C has attempted to standardize these events and their event labels so that they can be used consistently across browsers from all vendors.
XML Event Types
[edit | edit source]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.
Event | Cancel | Bubbles | Target |
---|---|---|---|
Initialization Events | |||
xforms-model-construct | N | Y | <model> |
xforms-model-construct-done | N | Y | <model> |
xforms-ready | N | Y | <model> |
xforms-model-destruct | N | N | <model> |
Processing Events | |||
xforms-rebuild | Y | Y | <model> |
xforms-recalculate | Y | Y | <model> |
xforms-revalidate | Y | Y | <model> |
xforms-refresh | Y | Y | <model> |
Interaction Events | |||
xforms-previous | Y | N | <control> |
xforms-next | Y | N | <control> |
xforms-focus | Y | N | <control> |
xforms-help | Y | Y | <control> |
xforms-hint | Y | Y | <control> |
xforms-reset | Y | Y | <model> |
xforms-submit | Y | Y | <submission> |
DOMActivate | Y | Y | <control> |
Notification Events | |||
DOMFocusIn | N | Y | <control> |
DOMFocusOut | N | Y | <control> |
xforms-value-changed | N | Y | <control> |
xforms-select | N | Y | <item>, <case> or <itemset> |
xforms-deselect | N | Y | <item>, <case> or <itemset> |
xforms-scroll-first | N | Y | <repeat> |
xforms-scroll-last | N | Y | <repeat> |
xforms-insert | N | Y | <instance> |
xforms-delete | N | Y | <instance> |
xforms-valid | N | Y | <control> |
xforms-invalid | N | Y | <control> |
xforms-in-range | N | Y | <control> |
xforms-out-of-range | N | Y | <control> |
xforms-readonly | N | Y | <control> |
xforms-readwrite | N | Y | <control> |
xforms-required | N | Y | <control> |
xforms-optional | N | Y | <control> |
xforms-enabled | N | Y | <control> |
xforms-disabled | N | Y | <control> |
xforms-submit-done | N | Y | <submission> |
xforms-submit-error | N | Y | <submission> |
Error Notifications | |||
xforms-binding-exception | N | Y | <bind> |
xforms-link-exception | N | Y | <model> |
xforms-link-error | N | Y | <model> |
xforms-compute-exception | N | Y | <model> |
Displaying Events in a Log File
[edit | edit source]One of the best ways to learn about how events get fired is to write them to a log instance and display the log at the bottom of the form. You can do this logging while you are building and debugging your form.
Add the following instance to your model:
<xf:instance xmlns="" id="log">
<events>
<event>log initialized</event>
</events>
</xf:instance>
Whenever you want to see an event, just add an action that appends an event to the end of the log:
<xf:action ev:event="xforms-deselect">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab One deselected'" />
</xf:action>
Note that the message must be inside a pair of single quotes inside of double quotes.
At the end of the form you can display the data from the log instance by enclosing the output within a repeat.
<div id="event-log">
<xf:repeat nodeset="instance('log')/event" class="log">
<xf:output ref="." />
</xf:repeat>
</div>
You can also style the event log with the following
#event-log {
color: DarkGray;
background-color: Lavender;
}
Setting Initial Cursor
Motivation
[edit | edit source]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 first field on a form with the mouse. Although some people consider this "polish" it is the hallmark of a conscientious developer.
Method
[edit | edit source]To perform this task you must do two things. First you need to give the control you want to receive the first keystroke event an id attribute. For example:
<xf:input id="first-field">
<xf:label>Search</xf:label>
</xf:input>
The next step is to use the xforms-ready event to set the focus to this field using the setfocus element.
These initial actions are usually placed at the end of the model in the html header but before the body.
<xf:model>
...
<xf:action ev:event="xforms-ready">
<xf:setfocus control="first-field" />
</xf:action>
...
</xf:model>
Link to XForms Application
[edit | edit source]Source Code
[edit | edit source]<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>
Selection and Deselection Events
Motivation
[edit | edit source]You want to perform actions based on a tab being selected or deselected. For example you may want to defer loading large parts of a complex model until a tab is selected.
Method
[edit | edit source]This example uses event logging to show how the selection and deselection events are used.
Screen Image
[edit | edit source]Sample Code
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Logging Tab Selection and Deselection Events</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Helvetica, sans-serif;}
/* style each individual tab */
#tab-bar xf|trigger {
color: black;
border: 3px outset gray;
border-bottom: none;
font-weight: bold;
margin-right: 5px;
padding: 0.2em;
/* round the top corners - works only with FireFox */
-moz-border-radius: .5em .5em 0em 0em;
}
.log {
background: lavender;
border: solid blue 1px;
}
</style>
<xf:model>
<xf:instance xmlns="" id="image">
<data />
</xf:instance>
<xf:instance xmlns="" id="log">
<events>
<event>log initialized</event>
</events>
</xf:instance>
<xf:action ev:event="xforms-ready">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'xforms-ready event'" />
</xf:action>
</xf:model>
</head>
<body>
<h1>Logging Tab Selection and Deselection Events</h1>
<p>The selection and deselection event will generate a message in the event log each time a tab is selected.</p>
<div id="tab-bar">
<xf:trigger appearance="minimal">
<xf:label>Tab One</xf:label>
<xf:toggle case="case-1" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger appearance="minimal">
<xf:label>Tab Two</xf:label>
<xf:toggle case="case-2" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger appearance="minimal">
<xf:label>Tab Three</xf:label>
<xf:toggle case="case-3" ev:event="DOMActivate" />
</xf:trigger>
</div>
<xf:switch>
<xf:case id="case-1">
<xf:action ev:event="xforms-select">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab One selected'" />
</xf:action>
<xf:action ev:event="xforms-deselect">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab One deselected'" />
</xf:action>
<h1>Tab One</h1>
</xf:case>
<xf:case id="case-2">
<xf:action ev:event="xforms-select">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab Two selected'" />
</xf:action>
<xf:action ev:event="xforms-deselect">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab Two deselected'" />
</xf:action>
<h1>Tab Two</h1>
</xf:case>
<xf:case id="case-3">
<xf:action ev:event="xforms-select">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab Three selected'" />
</xf:action>
<xf:action ev:event="xforms-deselect">
<xf:insert nodeset="instance('log')/event" at="last()" position="after" />
<xf:setvalue ref="instance('log')/event[last()]" value="'Tab Three deselected'" />
</xf:action>
<h1>Tab Three</h1>
</xf:case>
</xf:switch>
<xf:repeat nodeset="instance('log')/event" class="log">
<xf:output ref="." />
</xf:repeat>
</body>
</html>
Discussion
[edit | edit source]Note that you must wrap the xf:setvalue values in a double quote and a single quote to append strings to the events.
Conditional Actions
Motivation
[edit | edit source]You want to conditionally perform an action based on an XPath Expression.
Method
[edit | edit source]We will use the if attribute of an action that is part of the XForms 1.1 specification. We will set up an event that will be triggered every time an instance becomes empty. We will create an action and set the observer attribute to watch for changes in the people instance.
Here is the code for the action itself:
<xf:action
ev:event="xforms-delete"
ev:observer="people"
if="not(person)">
<xf:insert origin="instance('person-template')" context="."/>
</xf:action>
This says to watch the people instance and if there is not a person in the people instance then insert one using the person-template instance.
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xsd="http://www.w3.org/2001/XMLSchema-datatypes"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Test of populating a repeat if it becomes empty</title>
<xf:model id="m">
<xf:instance id="people">
<people xmlns="">
<person>
<name>John</name>
<email>j...@example.org</email>
</person>
<person>
<name>Bethany</name>
<email>beth...@example.org</email>
</person>
</people>
</xf:instance>
<xf:instance id="person-template">
<person xmlns=""><name/> <email/></person>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Test of populating a repeat if it becomes empty</h1>
<xf:group ref="instance('people')">
<xf:repeat nodeset="person">
<xf:input ref="name"><xf:label>Name: </xf:label></xf:input><br/>
<xf:input ref="email"><xf:label>Email address: </xf:label></xf:input>
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="."/>
</xf:trigger>
</xf:repeat>
<xf:action ev:event="xforms-delete" ev:observer="people"
if="not(person)">
<xf:insert origin="instance('person-template')" context="."/>
</xf:action>
</xf:group>
</body>
</html>
Acknowledgments
[edit | edit source]This example was posted on the Mozilla XForms newsgroup by John L. Clark in December 10th of 2008.
Binds to many instances
Motivation
[edit | edit source]You often want to be able to bind to different instances in different models. This sample program shows you how to do this. Creating separated models is critical to allow clean submissions. You should always structure so that your submission data is in a single model. But this creates problems when referencing data elements without specifying what model the instance is part of.
Note in the example below the group element encloses the output for each model.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:foobar="http://www.example.com">
<head>
<title>Binds to Multiple Instances in Multiple Models</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Helvetica,sans-serif}
xf|label {font-weight: bold}
</style>
<xf:model id="model-1">
<xf:instance id="instance-1-1" xmlns="">
<Data>
<Message>Hello World Model 1 Instance 1!</Message>
</Data>
</xf:instance>
<xf:bind id="bind-1-1" nodeset="instance('instance-1-1')/Message" />
<xf:instance id="instance-1-2" xmlns="">
<Data>
<Message>Hello World Model 1 Instance 2!</Message>
</Data>
</xf:instance>
<xf:bind id="bind-1-2" nodeset="instance('instance-1-2')/Message" />
</xf:model>
<xf:model id="model-2">
<xf:instance id="instance-2-1" xmlns="">
<Data>
<Message>Hello World Model 2 Instance 1!</Message>
</Data>
</xf:instance>
<xf:bind id="bind-2-1" nodeset="instance('instance-2-1')/Message" />
<xf:instance id="instance-2-2" xmlns="">
<Data>
<Message>Hello World Model 2 Instance 2!</Message>
</Data>
</xf:instance>
<xf:bind id="bind-2-2" nodeset="instance('instance-2-2')/Message" />
</xf:model>
</head>
<body>
<h1>Model 1</h1>
<xf:group model="model-1">
<xf:output ref="instance('instance-1-1')/Message">
<xf:label>ref="instance('instance-1-1')/Message":</xf:label>
</xf:output>
<br/>
<xf:output bind="bind-1-1">
<xf:label>bind="bind-1-1":</xf:label>
</xf:output>
<br/>
<xf:output ref="instance('instance-1-2')/Message">
<xf:label>ref="instance('instance-1-2')/Message":</xf:label>
</xf:output>
<br/>
<xf:output bind="bind-1-2">
<xf:label>bind="bind-1-2":</xf:label>
</xf:output>
</xf:group>
<h1>Model 2</h1>
<xf:group model="model-2">
<xf:output ref="instance('instance-2-1')/Message">
<xf:label>ref="instance('instance-2-1')/Message":</xf:label>
</xf:output>
<br/>
<xf:output bind="bind-2-1">
<xf:label>bind="bind-2-1":</xf:label>
</xf:output>
<br/>
<xf:output ref="instance('instance-2-2')/Message">
<xf:label>ref="instance('instance-2-2')/Message":</xf:label>
</xf:output>
<br/>
<xf:output bind="bind-2-2">
<xf:label>bind="bind-2-2":</xf:label>
</xf:output>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]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.
Bind to ranges
Motivation
[edit | edit source]Your output can be created from calculations from many inputs. The rules behind these calculations (sometimes called business rules) should be stored in the model, not the view.
Screen Image
[edit | edit source]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.
Sample Program
[edit | edit source]<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 product of the inputs -->
<xf:bind id="output-bind" nodeset="instance('output')/OutputValue" calculate="instance('input')/InputValueOne * instance('input')/InputValueTwo" type="xs:integer"/>
</xf:model>
</head>
<body>
<p>
<xf:range bind="input-one-bind" start="1" end="5" step="1" incremental="true">
<xf:label>Input: </xf:label>
</xf:range>
<br/>
<xf:range bind="input-two-bind" start="1" end="5" step="1" incremental="true">
<xf:label>Input: </xf:label>
</xf:range>
<br/>
<xf:output bind="input-one-bind"/> * <xf:output bind="input-two-bind"/> =
<xf:output bind="output-bind"/>
</p>
</body>
</html>
Discussion
[edit | edit source]Note that the output is just inputs and outputs. The calculation that multiplies the two inputs together is done in the output bind statement.
<xf:bind id="output-bind" nodeset="instance('output')/OutputValue" calculate="instance('input')/InputValueOne * instance('input')/InputValueTwo" type="xs:integer"/>
References
[edit | edit source]
Repeat
Here is a simple example of how to get a list of repeating data elements out to your screen. This is done using the repeat tag and the nodeset attribute. You use the nodeset to specify where you want to begin your listing in the model. In this case we are just using a model embedded into the page.
Output
[edit | edit source]Here is the output for this program under the FireFox browser:
Note that all of the names are displayed, not just the first name. Note how we are mixing both HTML tags and XForms tags together in the body.
Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Phone List</title>
<xf:model>
<xf:instance xmlns="" id="phonebook">
<PhoneList>
<Person>
<Name>Peggy</Name>
<Phone>123</Phone>
</Person>
<Person>
<Name>Dan</Name>
<Phone>456</Phone>
</Person>
<Person>
<Name>John</Name>
<Phone>789</Phone>
</Person>
<Person>
<Name>Sue</Name>
<Phone>234</Phone>
</Person>
</PhoneList>
</xf:instance>
</xf:model>
</head>
<body>
<fieldset>
<legend>Company Phone List</legend>
<p><b>Name, Phone</b>
<xf:repeat nodeset="Person">
<xf:output ref="Name"/>,
<xf:output ref="Phone"/>
</xf:repeat>
</p>
</fieldset>
</body>
</html>
Discussion
[edit | edit source]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.
You can also use an absolute path reference:
<xf:repeat nodeset="/PhoneList/Person">
As an alternative you can also use an instance reference:
<xf:repeat nodeset="instance('phonebook')/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.
Conditional Styling
Motivation
[edit | edit source]You have a list of items that you want to display inside of a repeat loop. You want some items to have different styling based on the content of items.
Method
[edit | edit source]We will use the XForms group element to conditionally display an item inside of the repeat statement.
Sample XML Fragement
[edit | edit source]Assume your form has the following data in an instance:
<my-nodes>
<my-node>
<element1>true</element1>
<element2>Element2 Value</element2>
</my-node>
<my-node>
<element1>false</element1>
<element2>Element2 Value</element2>
</my-node>
<my-node>
<element1>true</element1>
<element2>Element2 Value</element2>
</my-node>
</my-nodes>
Conditional Display of Items
[edit | edit source]The following text will only output element2 when element1 has a value of true.
<xf:repeat nodeset="//my-node">
<xf:group ref=".[element1='true']">
<xf:output ref="element2"/>
</xf:group>
</xf:repeat>
The syntax .[a='b'] says that from the current node if the element a equals the value b then output the elements within the group.
Conditional Formatting of Items
[edit | edit source]This same strategy can be used to enclose output in different div or span elements.
<xf:repeat nodeset="my-node">
<xf:group ref=".[element1='true']">
<xf:output ref="element2" class="strong"/>
</xf:group>
<xf:group ref=".[element1='false']">
<xf:output ref="element2"/>
</xf:group>
</xf:repeat>
In the above example all nodes with element1='true' will have a class="strong" in the output and any element with element1='false' will not have the attribute in the output.
Sample XForms Appliction
[edit | edit source]Source Code
[edit | edit source]In this example we need to display a list of synonyms for a specific term. The Synonyms are all listed and a preferred term is displayed with a bold font.
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Conditional Display</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Helvetica, sans-serif}
.strong {font-weight:bold;}
/* this puts everything under the repeat element into a single line */
xf|repeat * {display:inline;}
</style>
<xf:model>
<xf:instance xmlns="" id="current-synset">
<data>
<synset-id>3</synset-id>
<synonym>
<preferred>false</preferred>
<syn-name>Boolean-Value</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Conditional-Value</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Flag</syn-name>
</synonym>
<synonym>
<preferred>true</preferred>
<syn-name>Indicator</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Yes/No-Value</syn-name>
</synonym>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<h3>Synonym Set</h3>
<span>(preferred term is bold)</span><br/>
<xf:label>Synonyms: </xf:label>
<xf:repeat nodeset="instance('current-synset')/synonym" id="repeat">
<xf:group ref=".[preferred='true']">
<xf:output ref="syn-name" class="strong"/>
</xf:group>
<xf:group ref=".[preferred='false']">
<xf:output ref="syn-name"/>
</xf:group>
</xf:repeat>
</body>
</html>
Discussion
[edit | edit source]XForms 1.1 also includes the if attribute. Some XForms can conditionally use this for display of elements.
Formatting Numbers
Motivation
[edit | edit source]You want the view portion of your form to add formatting information to numbers. For example, you want your US currency to be stored in the model as 12345.6789 but the view to display at $12,345.68. Note that the dollar sign is used as a prefix, commas are added and the decimal is rounded to two digits.
Ideally, we would like to use a simple CSS function to indicate that all currency should be formatted using the standard number picture formats such as "$#,###.##".
Method
[edit | edit source]If all browsers supported the XPath 2.0 format-number() function, this would be trivial. Till then the developer will need to resort to workaround such as using JavaScript and the XML Binding language (XBL).
Sample Code
[edit | edit source]<xf:bind nodeset="instance('invoice')/Total" calculate="round((instance('invoice')/Tax + instance('invoice')/SubTotal) * 100) div 100"/>
References
[edit | edit source]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
Output and Links
Motivation
[edit | edit source]You want to display a repeated set of URLs in a section of your form. Each URL is created by concatenating a base URL and a URL parameter.
Method
[edit | edit source]The equivalent of the HTML anchor tag (<a>) in an XForms application is the <xf:load> element.
If in a web page, you want your output to appear like this:
<div class="links">
<a href="http://www.example.com/myservice.xq?id=1">One</a>
<a href="http://www.example.com/myservice.xq?id=2">Two</a>
<a href="http://www.example.com/myservice.xq?id=3">Three</a>
</div>
in an XForms application each anchor will be xf:load.
Your input instance is like the following:
<xf:instance id="link-items" xmlns="">
<data>
<item>
<id>1<id>
<label>One</label>
</item>
<item>
<id>2<id>
<label>Two</label>
</item>
<item>
<id>3<id>
<label>Three</label>
</item>
</data>
</xf:instance>
Discussion
[edit | edit source]With XForms it is not possible to create dynamic links inside a repeat using a combination of output, value and concat. This would also impact the ability to notify the user that is navigating away from a form.
There are two ways to display a list of links. Both use a trigger with the button appearance turned off. The first uses a load after setting a temporary instance. The second uses a submit/submission combination.
Using load
[edit | edit source]You can also use the load element as the element.
<xf:instance id="URL-container" xmlns="">
<URL/>
</xf:instance>
<!-- ... -->
<xf:trigger appearance="minimal">
<xf:label>One</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('URL-container')"
value="concat('http://www.example.com/my-view.xq?id=', id)"/>
<xf:load ref="instance('URL-container')"/>
</xf:action>
</xf:trigger>
<xf:instance>
Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]The following program displays a list of links in a horizontal row. Each link has a label and a URL suffix that is extracted from an instance document.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Displaying Links in an XForms Application</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Helvetica, sans-serif}
.links xf|repeat * {display: inline;}
.url {color: blue; text-decoration:underline; margin: 0 2px;}
</style>
<xf:model>
<xf:instance xmlns="" id="links">
<data>
<link>
<label>XForms</label>
<wikipedia-id>XForms</wikipedia-id>
</link>
<link>
<label>XQuery</label>
<wikipedia-id>XQuery</wikipedia-id>
</link>
<link>
<label>XSLT</label>
<wikipedia-id>XSL Transformations</wikipedia-id>
</link>
<link>
<label>XML Database</label>
<wikipedia-id>XML_database</wikipedia-id>
</link>
<link>
<label>Declarative Programming</label>
<wikipedia-id>Declarative_programming</wikipedia-id>
</link>
<link>
<label>Functional Programming</label>
<wikipedia-id>Functional_programming</wikipedia-id>
</link>
</data>
</xf:instance>
<xf:instance id="URL-container" xmlns="">
<URL />
</xf:instance>
</xf:model>
</head>
<body>
<h3>Displaying Links in an XForms Application</h3>
<div class="links">
<xf:repeat nodeset="instance('links')/link" id="link-repeat">
<xf:trigger submission="replace-form-with" appearance="minimal" class="url">
<xf:label>
<xf:output ref="label" />
</xf:label>
<xf:hint>
<xf:output ref="wikipedia-id" />
</xf:hint>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('URL-container')" value="concat('http://en.wikipedia.org/wiki/', instance('links')/link[index('link-repeat')]/wikipedia-id)" />
<xf:load ref="instance('URL-container')" />
</xf:action>
</xf:trigger>
</xf:repeat>
</div>
</body>
</html>
Acknowledgment
[edit | edit source]This solution was posted to the Mozilla XForms development newsgroup by John Clark on February 27th, 2008.
Using Submit and Submission for Links
[edit | edit source]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.
Switch and Case
Motivation
[edit | edit source]You want to conditionally display different areas of the screen based on static IDs.
Screen Image
[edit | edit source]As you click on one of the three buttons on the top row, the view displayed below will change.
Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Switch, case and toggle</title>
<!-- Demonstration of switch/case and toggle -->
<style type="text/css">
<![CDATA[
@namespace xf url("http://www.w3.org/2002/xforms");
xf|group {
border: solid black 2px;
background-color: silver;
height: 100px;
}
xf|group xf|label {
position: relative;
font-family: Helvetica, sans-serif;
font-weight: bold;
background-color: white;
padding: 2px;
top: -10px;
left: 10px;
}
xf|group p {
position: relative;
top: -30px;
padding: 5px;
}
]]>
</style>
<xf:model />
</head>
<body>
<xf:trigger>
<xf:label>View One</xf:label>
<xf:toggle case="case-1" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger>
<xf:label>View Two</xf:label>
<xf:toggle case="case-2" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger>
<xf:label>View Three</xf:label>
<xf:toggle case="case-3" ev:event="DOMActivate" />
</xf:trigger>
<br />
<br />
<!-- only a single group will be displayed at any time -->
<xf:switch>
<xf:case id="case-1">
<xf:group>
<xf:label>View One</xf:label>
<p>One One One One One One One One One One One One One One One One One One</p>
</xf:group>
</xf:case>
<xf:case id="case-2">
<xf:group>
<xf:label>View Two</xf:label>
<p>Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two</p>
</xf:group>
</xf:case>
<xf:case id="case-3">
<xf:group>
<xf:label>View Three</xf:label>
<p>Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three</p>
</xf:group>
</xf:case>
</xf:switch>
</body>
</html>
Discussion
[edit | edit source]XForms provides an easy ways to swap between views. This also shows how the XForms group and label can be used like the HTML fieldset and legend.
References
[edit | edit source]
Relevant
Using Bind with the Relevant Attribute
[edit | edit source]XForms also allows you to conditionally display part of a form based on some value in your instance data. Typically this is used when the answer to one field of the form conditionally displays another part.
The format of this is to use the xf:bind statement within in the xf:model.
<xf:model>
<xf:bind nodeset="NodeYowWantToConditionallyDisplay" relevant="XPathExpression"/>
</xf:model>
The following examples demonstrate this.
Link to Relevancy XForms Application
[edit | edit source]Relevancy Demos Note: RelevancySelector.xhtml in the example application is incomplete.
Bind to a Decimal
[edit | edit source]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 > 0" />
</xf:model>
</head>
<body>
<p>Demonstration of relevant fields.</p>
<xf:select1 ref="/var/first" >
<xf:label>Should I show the second question? </xf:label>
<br />
<xf:item select="yes">
<xf:label>Yes Please!</xf:label>
<xf:value>1</xf:value>
</xf:item>
<xf:item>
<xf:label>No Thank You</xf:label>
<xf:value>0</xf:value>
</xf:item>
</xf:select1>
<br />
<xf:input ref="/var/second">
<xf:label>Second value: </xf:label>
</xf:input>
</body>
</html>
Using Multiple Predicates in Binds
[edit | edit source]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][. > 2.0]" />
</xf:model>
</head>
<body>
<xf:input ref="instance('instanceData')/item[1]">
<xf:label>First item: </xf:label>
</xf:input>
<br />
<xf:input ref="instance('instanceData')/item[2]">
<xf:label>Second item: </xf:label>
</xf:input>
</body>
</html>
Bind to Boolean
[edit | edit source]Since parts of a form are usually either visible or not visible, it is natural to use a boolean value to determine if the field should be displayed.
In this example if InputIndicator is true, the second output instance is visible.
If the InputIndicator is false, the second output is not visible.
Note that expression .='true'
is used. This is a string comparison. Ideally you would just be able to test a node using mynoode=true() but I have had problems with this method.
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Example of binding to to boolean controls</title>
</head>
<body>
<xf:model id="model">
<xf:instance id="input">
<DataIn xmlns="">
<InputIndicator>false</InputIndicator>
</DataIn>
</xf:instance>
<!-- make the input data type be a XML Schema type boolean -->
<xf:bind id="input_bind" nodeset="/DataIn/InputIndicator" type="xs:boolean"></xf:bind>
<!-- second instance bound to outputs -->
<xf:instance id="output">
<DataOut xmlns="">
<OutputValue>Hello World!</OutputValue>
</DataOut>
</xf:instance>
<!-- if the input is true, then the output is relevent -->
<xf:bind id="output_bind" nodeset="instance('output')/OutputValue" relevant="instance('input')/InputIndicator[.='true']"/>
</xf:model>
<p>
<xf:input bind="input_bind">
<xf:label>Check to see the value of output: </xf:label>
</xf:input>
<br/>
<xf:output bind="output_bind">
<xf:label>Value of Output: </xf:label>
</xf:output>
</p>
</body>
</html>
In this example, a simple checkbox is used to conditionally display a field.
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<title>Testing the relevant attribute of the bind element with boolean values.</title>
<xf:model>
<xf:instance>
<var xmlns="">
<first>true</first>
<second/>
</var>
</xf:instance>
<xf:bind nodeset="/var/first" type="xs:boolean" />
<xf:bind nodeset="/var/second" relevant="/var/first='true'" />
</xf:model>
<body>
<p>The input field should only display if the first value is checked.</p>
<xf:input ref="/var/first">
<xf:label>Display the next input?: </xf:label>
</xf:input>
<br />
<xf:input ref="/var/second">
<xf:label>Display this only if the first answer is true: </xf:label>
</xf:input>
</body>
</html>
In this example the type cast to boolean does not have any impact since relevant="/var/first=true()" does not work as expected. String comparison must be used.
Binding a view to a select 1
[edit | edit source]This example shows how to conditionally display a view based on the value of a select1 control.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<title>Testing the XForms bind relevant attribute based on a select1 control.</title>
<xf:model>
<xf:instance>
<data xmlns="">
<select1value>1</select1value>
<view1 />
<view2 />
<view3 />
</data>
</xf:instance>
<xf:bind nodeset="/data/select1value" type="xs:decimal" />
<xf:bind nodeset="/data/view1" relevant="/data/select1value = 1" />
<xf:bind nodeset="/data/view2" relevant="/data/select1value = 2" />
<xf:bind nodeset="/data/view3" relevant="/data/select1value = 3" />
</xf:model>
<body>
<p>Demonstration of relevant fields.</p>
<xf:select1 ref="/data/select1value">
<xf:label>What view would you like to see? </xf:label>
<br />
<xf:item select="yes">
<xf:label>View 1</xf:label>
<xf:value>1</xf:value>
</xf:item>
<xf:item>
<xf:label>View 2</xf:label>
<xf:value>2</xf:value>
</xf:item>
<xf:item>
<xf:label>View 3</xf:label>
<xf:value>3</xf:value>
</xf:item>
</xf:select1>
<br />
<xf:input ref="/data/view1">
<xf:label>First view: </xf:label>
</xf:input>
<xf:input ref="/data/view2">
<xf:label>Second view: </xf:label>
</xf:input>
<xf:input ref="/data/view3">
<xf:label>Third view: </xf:label>
</xf:input>
</body>
</html>
Note that the functionally is similar to a <xf:switch> and <xf:case> combination but no <xf:toggle> is used.
The bind statement
[edit | edit source]The following line is the line that does the actual bind. You should use the instance() function whenever you are binding one instance to another.
Also note that you must compare the text of the InputIndicator (the period) to true and not the InputIndicator itself.
<xf:bind id="output_bind"
nodeset="instance('output')/OutputValue"
relevant="instance('input')/InputIndicator[.='true']" />
An Architecture for Conditional Views and User-Maintainable Rules
[edit | edit source]Sometimes you need to have a consistent way of conditionally displaying views in a form. For example, if you want non-programmers to maintain the business logic of when a view is displayed, the binding rules to a view can be generated by an external rules engine.
To make this work you need to create a central instance that is used to control form views:
<xf:instance id="views" xmlns="">
<data>
<named-view-1/>
<named-view-2/>
<named-view-3/>
</data>
</xf:instance>
We call this architecture one of "Named Views" because an external tool can be used to state the rules of how any named view is rendered. This will be a central location in the form that generates the view instance and the binding expressions.
Each view is wrapped in a group element that binds the group to the instance in the view:
<xf:group ref="instance('views')/named-view-1">
<!-- these elements will be conditionally displayed based on the relevancy of named-view-1 -->
</xf:group>
<xf:group ref="instance('views')/named-view-2">
<!-- these elements will be conditionally displayed based on the relevancy of named-view-2 -->
</xf:group>
<xf:group ref="instance('views')/named-view-2">
<!-- these elements will be conditionally displayed based on the relevancy of named-view-3 -->
</xf:group>
The display rules for each view can then be stored in a bind statement:
<xf:bind nodeset="instance('views')/named-view-1" relevant="XPath-expression-that-returns-a-boolean-for named-view-1"/>
<xf:bind nodeset="instance('views')/named-view-2" relevant="XPath-expression-that-returns-a-boolean-for named-view-2"/>
<xf:bind nodeset="instance('views')/named-view-3" relevant="XPath-expression-that-returns-a-boolean-for named-view-3"/>
Each form can then have a "rules file" that looks similar to the following:
<form-rules-file>
<form-id>my-form-ver-2</form-id>
<display-rule>
<named-view>named-view-1</named-view>
<xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-1</xpath-expression>
</display-rule>
<display-rule>
<named-view>named-view-2</named-view>
<xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-2</xpath-expression>
</display-rule>
<display-rule>
<named-view>named-view-2</named-view>
<xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-3</xpath-expression>
</display-rule>
</form-rules-file>
You can then build another XForms application that allows non-programmers to maintain these rules files and and a simple transform that places the instance and bind statements in the XForms model when it is loaded. The original groups may still need to be manually added to the form but once the views are added the rules can be maintained with a separate application.
Changing Fields to Display
[edit | edit source]The following example conditionally displays two zip code fields if the country code is 'usa" or displays a postal code if the field is not 'usa'.
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Testing the XForms bind relevant attribute.</title>
<style language="text/css">
<![CDATA[
@namespace xf url("http://www.w3.org/2002/xforms");
/* this allows the descenders (jpqy) to be visible in the drop down list */
xf|select1 .xf-value {height: 1.5em;}
.ZipCode .xf-value {width:5ex}
.ZipCodeSuffix .xf-value {width:4ex}
.PostalCode .xf-value {width:10ex}
]]>
</style>
<xf:model>
<xf:instance xmlns="" id="save-data">
<data>
<CountryCode>usa</CountryCode>
<ZipCode>12345</ZipCode>
<ZipCodeSuffix>1234</ZipCodeSuffix>
<PostalCode>AB-1234</PostalCode>
</data>
</xf:instance>
<!-- The views instance are boolean values that tell what fields are visible -->
<xf:instance xmlns="" id="views">
<data>
<DisplayZipCode/>
<DisplayPostalCode/>
</data>
</xf:instance>
<!-- this rule only displays the zip code if the country code is 'usa'-->
<xf:bind id="DisplayZipCode"
nodeset="instance('views')/DisplayZipCode"
relevant="instance('save-data')/CountryCode='usa'" />
<xf:bind id="DisplayPostalCode"
nodeset="instance('views')/DisplayPostalCode"
relevant="not(instance('save-data')/CountryCode='usa')" />
</xf:model>
</head>
<body>
<p>Demonstration of binding Zip Code Input</p>
<xf:select1 ref="instance('save-data')/CountryCode" selection="open">
<xf:label>Country:</xf:label>
<xf:item>
<xf:label>USA</xf:label>
<xf:value>usa</xf:value>
</xf:item>
<xf:item>
<xf:label>Canada</xf:label>
<xf:value>can</xf:value>
</xf:item>
<xf:item>
<xf:label>Mexico</xf:label>
<xf:value>mex</xf:value>
</xf:item>
<xf:item>
<xf:label>Other</xf:label>
<xf:value>other</xf:value>
</xf:item>
</xf:select1>
<br/>
<xf:group bind="DisplayZipCode">
<xf:input ref="instance('save-data')/ZipCode" class="ZipCode">
<xf:label>Zip Code: </xf:label>
</xf:input>
<xf:input ref="instance('save-data')/ZipCodeSuffix" class="ZipCodeSuffix">
<xf:label>-</xf:label>
</xf:input>
</xf:group>
<xf:input ref="instance('save-data')/LocationPostalID" bind="DisplayPostalCode" class="DisplayPostalCode">
<xf:label>Postal Code: </xf:label>
</xf:input>
</body>
</html>
Delete
[edit | edit source]One of the most common occurrence of conditional display is the delete function for repeating elements. Typically you do not want to delete the last one. See the XForms/Conditional_delete example.
Discussion
[edit | edit source]
Binding in Repeats
Motivation
[edit | edit source]You have a list of items and you want a simple way of conditionally displaying fields within a repeated group.
Method
[edit | edit source]We will do this is two ways. First we will use a bind expression in the model. The second method of doing this will be to use a group element with a ref attribute.
Sample Data
[edit | edit source]<data xmlns="">
<group>
<code>yes</code>
<field>display 1</field>
</group>
<group>
<code>no</code>
<field>display 2</field>
</group>
<group>
<code>yes</code>
<field>display 3</field>
</group>
</data>
Sample Repeat
[edit | edit source]<xf:repeat nodeset="instance('my-data')/group" id="my-repeat">
<fieldset>
<legend>
Group # <xf:output value="count(preceding-sibling::*) +1"></xf:output>
</legend>
<xf:select1 ref="code">
<xf:label>Display Input Field: </xf:label>
<xf:item>
<xf:label>Yes</xf:label>
<xf:value>yes</xf:value>
</xf:item>
<xf:item>
<xf:label>No</xf:label>
<xf:value>no</xf:value>
</xf:item>
</xf:select1>
<xf:input ref="field" >
<xf:label>Conditional Display: </xf:label>
</xf:input>
</fieldset>
</xf:repeat>
Solution Using Relative Binds
[edit | edit source]In this example we use a relative statement to indicate that the field should only be displayed if the code value is "yes". Note that the context of the relevant expression is the result of each nodeset item.
<xf:bind id="field"
nodeset="instance('my-data')/group/field"
relevant="../code = 'yes'"/>
Solution Using Group Element
[edit | edit source]We can use the ref attribute to conditionally display any field within a repeat. We do this by starting the group ref attribute with "." to give it the current context. Then we add a predicate to turn on or off that entire group. In this case if the code is "yes" the input field will be displayed. If it is not the field will be hidden.
<xf:group ref=".[code='yes']">
<xf:input ref="field">
<xf:label>Conditional Display: </xf:label>
</xf:input>
</xf:group>
Complete Example
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Binds in Repeats</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {{
font-family:Helvetica, sans-serif;
}}</style>
<xf:model>
<xf:instance id="my-data">
<data xmlns="">
<group>
<code>yes</code>
<field>display 1</field>
</group>
<group>
<code>no</code>
<field>display 2</field>
</group>
<group>
<code>yes</code>
<field>display 3</field>
</group>
<group>
<code>no</code>
<field>display 4</field>
</group>
</data>
</xf:instance>
<xf:bind id="field"
nodeset="instance('my-data')/group/field"
relevant="../code = 'yes'"/>
</xf:model>
</head>
<body>
<h1>Test of binding rules within a repeat</h1>
<xf:repeat nodeset="instance('my-data')/group" id="my-repeat">
<fieldset>
<legend>
Group # <xf:output value="count(preceding-sibling::*) +1"></xf:output>
</legend>
<xf:select1 ref="code">
<xf:label>Display Input Field: </xf:label>
<xf:item>
<xf:label>Yes</xf:label>
<xf:value>yes</xf:value>
</xf:item>
<xf:item>
<xf:label>No</xf:label>
<xf:value>no</xf:value>
</xf:item>
</xf:select1>
<xf:input ref="field" >
<xf:label>Conditional Display: </xf:label>
</xf:input>
</fieldset>
</xf:repeat>
<xf:output value="index('my-repeat')">
<xf:label>Current Selected Group: </xf:label>
</xf:output>
</body>
</html>
Show-Hide Controls
Motivation
[edit | edit source]You want to only display a full representation of a control when the user wants to set or change the control's value.
Method
[edit | edit source]We will use the switch/case and toggle elements to conditionally display a custom control. When the user opens a form a small "show value" of this control is visible and a trigger to set or change the value of the control. After the user selects a value the control reverts to a view that minimizes the screen area.
Screen Images
[edit | edit source]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.
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.
Sample Code
[edit | edit source]<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>
Disable Buttons
Motivation
[edit | edit source]You want to remove a delete button to prevent removal of the last item of a list.
Method
[edit | edit source]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) > 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) > 1"/>
The above uses the XPath count() function with the greater than operator. But since it must be escaped you must use the ">" instead of ">".
Or alternatively the delete button is only visible if the second person record exists in the instance.
<xf:bind id="triggerDisplay" nodeset="display-delete" relevant="/data/person[2]"/>
This gets around having to count all the elements and doing a comparison. So it is a little bit more efficient for longs lists of items.
This creates a rule call "triggerDisplay" that pin relevancy to an XForms instance.
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]<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) > 1"/>
<xf:submission id="mySubmission" method="post"
action="http://www.xformstest.org/cgi-bin/echo.sh"/>
</xf:model>
</head>
<body>
<h2>Demo of Button Disable</h2>
<xf:repeat nodeset="person">
<xf:input ref="name">
<xf:label>Name: </xf:label>
</xf:input>
</xf:repeat>
<hr/>
<xf:trigger>
<xf:label>Insert</xf:label>
<xf:insert nodeset="instance('myInstance')/person"
at="last()" position="after" ev:event="DOMActivate"/>
</xf:trigger>
<!-- This trigger is bound to the display rule -->
<xf:trigger bind="triggerDisplay">
<xf:label>Delete</xf:label>
<xf:delete nodeset="instance('myInstance')/person"
at="last()" ev:event="DOMActivate"/>
</xf:trigger>
<xf:submit submission="mySubmission">
<xf:label>Submit instance</xf:label>
</xf:submit>
</body>
</html>
Using the Context attribute
[edit | edit source]You can also use the context attribute of the trigger to tell it when to fire.
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Disable final delete trigger.</title>
<xf:model id="person">
<xf:instance id="person_xml" xmlns="">
<person>
<contacts>
<section name="Personal">
<contact/>
</section>
</contacts>
</person>
</xf:instance>
</xf:model>
</head>
<body>
<xf:repeat nodeset="contacts/section" id="repeat_section">
<fieldset>
<legend>
<xf:trigger>
<xf:label>-</xf:label>
<xf:hint>Delete this section.</xf:hint>
<xf:delete
context="instance('person_xml')/contacts"
nodeset="section[position()!=last()]"
at="index('repeat_section')"
ev:event="DOMActivate"/>
</xf:trigger>
<xf:input ref="./@name">
<xf:label>section name</xf:label>
</xf:input>
</legend>
<xf:repeat nodeset="contact" id="repeat_contact">
<xf:input ref=".">
<xf:label>contact</xf:label>
</xf:input>
<xf:trigger>
<xf:label>-</xf:label>
<xf:hint>Delete this contact.</xf:hint>
<xf:delete
context="instance('person_xml')/contacts/section[index('repeat_section')]"
nodeset="contact[position()!=last()]"
at="index('repeat_contact')"
ev:event="DOMActivate"/>
</xf:trigger>
<xf:trigger>
<xf:label>+</xf:label>
<xf:hint>Add a new contact after this one.</xf:hint>
<xf:insert nodeset="." at="index('repeat_section')" position="after" ev:event="DOMActivate"/>
</xf:trigger>
</xf:repeat>
</fieldset>
<xf:trigger>
<xf:hint>Add a new section after this one.</xf:hint>
<xf:label>add section</xf:label>
<xf:insert nodeset="." at="last()" position="after" ev:event="DOMActivate"/>
</xf:trigger>
</xf:repeat>
</body>
</html>
Context
[edit | edit source]Optional XPath expression used to change the in-scope evaluation context for the delete element. This attribute is ignored if the bind attribute is provided. If the attribute is not given, then the default delete context is the in-scope evaluation context. Otherwise, the XPath expression is evaluated using the in-scope evaluation context, and the first node rule is applied to obtain the delete context. The delete action is terminated with no effect if the delete context is the empty node-set or if the context attribute is not given and the Node Set Binding node-set is empty.
Example of Min and Max
[edit | edit source]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) < 5"/>
<xf:submission id="save" method="post" action="save.xq" replace="all"/>
</xf:model>
</head>
<body>
<xf:label class="group-label">Phone Numbers</xf:label>
<xf:repeat id="phone-number-repeat" nodeset="/PersonPhones/Phone">
<xf:input ref="PhoneDescriptionText" class="PhoneDescriptionText" id="PhoneDescriptionText"/>
<xf:input ref="PhoneNumber" class="PhoneNumber"/>
<!-- bind="phone-delete-trigger" -->
<xf:trigger bind="phone-delete-trigger">
<xf:label>Delete</xf:label>
<!-- this deletes the currently selected phone number -->
<xf:delete nodeset="instance('phones')/Phone[index('phone-number-repeat')]" ev:event="DOMActivate"/>
</xf:trigger>
</xf:repeat>
<xf:trigger bind="phone-add-trigger">
<xf:label>Add</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('phones')/Phone" at="last()" position="after"/>
<!-- this initialized the values of the phone number to null. Can also use an origin attribute. -->
<xf:setvalue ref="/PersonPhones/Phone[index('phone-number-repeat')]/PhoneDescriptionText" value=""/>
<xf:setvalue ref="/PersonPhones/Phone[index('phone-number-repeat')]/PhoneNumber" value=""/>
<!-- this puts the cursor in the first field of the new row we just added -->
<xf:setfocus control="PhoneDescriptionText"/>
</xf:action>
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]
Read Only
Motivation
[edit | edit source]Forms frequently need to display fields that are not editable by the user. The following program demonstrates this feature.
This is done in XForms using a binding and a style sheet.
A single field (or group of fields) can be marked as read-only with a single bind statement. For example, suppose you had a set of fields related to shipping supplies to remote staff in your IT department. The billing address could not be changed, only who an item was shipped to.
The following single line in the model would make all of the sub-elements of BillToAddress read-only:
<xf:bind nodeset="/PurchaseOrders/BillToAddress" readonly="true()" />
Note that because of CSS, all the fields under this binding will be marked read-only. This is one good reason you may want to logically group read-only data elements in an application.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]XHTML XForm
[edit | edit source]<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 | edit source]<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 | edit source] /* a stylesheet for tabular XForms input field alignment */
@namespace xf url("http://www.w3.org/2002/xforms");
/* give the input form labels and the fieldset legend a bold sans-serif font */
label {
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: small;
}
xf|group {
border: black solid 2px;
padding: 5px;
width: 300px;
}
/* the labels are right-aligned in a 150px wide column */
xf|input xf|label {
width: 150px;
margin: 3px;
text-align: right;
}
/* the input values are left aligned */
xf|value {
text-align: left;
}
/* vertical area between input boxes */
input {
margin: .2em;
}
/* each input is a row in the group table */
xf|input {
display: table-row;
}
/* each label within an input is a cell in the input row */
xf|input xf|label {
display: table-cell;
}
/* each value (pseudo-element) is also a cell in the input row */
xf|input::value {
display: table-cell;
}
Discussion
[edit | edit source]
Select and Group
Motivation
[edit | edit source]You want to conditionally display a group of elements based on the value selected from a list. This will work similar to a "switch/case" but you can have each view depend on complex XPath expressions that will evaluated to either true or false.
Screen Image
[edit | edit source]In the screen image above, the second item is selected. When a different item is selected, the view under the select list changes.
Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Dynamically bind to a group</title>
<!-- Using bind and relevant in the model to conditionally display a group -->
<!-- Alternative to switch/case/toggle when the id of toggle is dynamically calculated -->
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
xf|group {
border: solid black 2px;
background-color: silver;
height: 100px;
}
xf|group xf|label {
position: relative;
font-family: Helvetica, sans-serif;
font-weight: bold;
background-color: white;
padding: 2px;
top: -10px;
left: 10px;
}
xf|group p {
position: relative;
top: -30px;
padding: 5px;
}
</style>
<xf:model>
<xf:instance>
<data xmlns="">
<current-view>one</current-view>
<view-1>one</view-1>
<view-2>two</view-2>
<view-3>three</view-3>
</data>
</xf:instance>
<!-- if the current-view is 'one' make the view-1 group relevent (visible)-->
<xf:bind nodeset="view-1" relevant="../current-view = 'one'" />
<xf:bind nodeset="view-2" relevant="../current-view = 'two'" />
<xf:bind nodeset="view-3" relevant="../current-view = 'three'" />
</xf:model>
</head>
<body>
<xf:select1 ref="current-view">
<xf:label>Select View: </xf:label>
<xf:item>
<xf:label>One</xf:label>
<xf:value>one</xf:value>
</xf:item>
<xf:item>
<xf:label>Two</xf:label>
<xf:value>two</xf:value>
</xf:item>
<xf:item>
<xf:label>Three</xf:label>
<xf:value>three</xf:value>
</xf:item>
</xf:select1>
<br/>
<!-- only one of the three outputs will display -->
<xf:output ref="view-1">
<xf:label>Current view: </xf:label>
</xf:output>
<xf:output ref="view-2">
<xf:label>Current view: </xf:label>
</xf:output>
<xf:output ref="view-3">
<xf:label>Current view: </xf:label>
</xf:output>
<br/>
<br/>
<!-- only a single group will be displayed at any time -->
<xf:group ref="view-1">
<xf:label>View One</xf:label>
<p>One One One One One One One One One One One One One One One One One One</p>
</xf:group>
<xf:group ref="view-2">
<xf:label>View Two</xf:label>
<p>Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two Two</p>
</xf:group>
<xf:group ref="view-3">
<xf:label>View Three</xf:label>
<p>Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three Three</p>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]This program is very similar to the example that uses a button to toggle a switch/case but the value is calculated dynamically by any XPath expression. The prior example that uses switch/case/toggle uses an XML Event to make a specific case visible.
References
[edit | edit source]
Dynamic Labels
Motivation
[edit | edit source]Sometimes you want to change a single label on a form without loading the form. For example, after you enter the country of an address you may want to ask for a "Province" in Canada or a "State" in the US. This can also be used to load alternative labels based on the user's language.
Screen Image
[edit | edit source]Link to Working XForms Application
[edit | edit source]XForms Example of Dynamic Labels
Sample Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Example of Dynamic Label Lookup</title>
<!-- based on a version by Kurt Cagle -->
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Ariel, Helvetica, san-serif}
/* Input Control labels are right-aligned in a 200px wide column that floats to the left. */
/* This line ensures all the separate input controls appear on their own lines */
xf|input, xf|select, xf|select1, xf|textarea {display:block; margin:5px 0;}
/* Makes the labels right aligned in a 200px wide column that floats to the left of the input controls. */
xf|input > xf|label, xf|select > xf|label, xf|select1 > xf|label, xf|textarea > xf|label {text-align:right; padding-right:10px; width:200px; float:left; text-align:right;}
/* Put a black border and background color around all specified XForms groups and gives them both margin and padding */
xf|group {border: solid black 1px; margin:15px 5px; padding:5px; background-color:Lavender;}
.group-label {text-align:left;font-weight:bold;font-size:12pt;}
</style>
<xf:model>
<xf:instance id="data" xmlns="">
<Data>
<PersonName>
<PersonGivenName>John</PersonGivenName>
<PersonMiddleName>Paul</PersonMiddleName>
<PersonSurName>Doe</PersonSurName>
</PersonName>
<Address>
<LocationStreetFull>123 Main St.</LocationStreetFull>
<LocationCityName>Anytown</LocationCityName>
<LocationStateName>MN</LocationStateName>
<LocationPostalID>55123</LocationPostalID>
</Address>
</Data>
</xf:instance>
<xf:instance id="selected-country" xmlns="">
<data>
<country-id>usa</country-id>
</data>
</xf:instance>
<xf:bind id="country" nodeset="instance('selected-country')/country-id" />
<xf:instance id="label-lookup" xmlns="">
<label-lookup>
<country>
<country-id>usa</country-id>
<data-element name="record" label="Record" />
<data-element name="PersonName" label="Person Name" />
<data-element name="PersonGivenName" label="First (Given) Name" />
<data-element name="PersonSurName" label="Last (Family) Name" />
<data-element name="PersonMiddleName" label="Middle Name" />
<data-element name="Address" label="Address" />
<data-element name="LocationStreetFull" label="Street" />
<data-element name="LocationCityName" label="City" />
<data-element name="LocationStateName" label="State" />
<data-element name="LocationCountryName" label="Country" />
<data-element name="LocationPostalID" label="Zip" />
</country>
<country>
<country-id>canada</country-id>
<data-element name="record" label="Record" />
<data-element name="PersonName" label="Person Name" />
<data-element name="PersonGivenName" label="First Name" />
<data-element name="PersonSurName" label="Last Name" />
<data-element name="PersonMiddleName" label="Middle Name" />
<data-element name="Address" label="Address" />
<data-element name="LocationStreetFull" label="Street" />
<data-element name="LocationCityName" label="City" />
<data-element name="LocationStateName" label="Province" />
<data-element name="LocationCountryName" label="Country" />
<data-element name="LocationPostalID" label="Postal Code" />
</country>
<country>
<country-id>uk</country-id>
<data-element name="record" label="Record" />
<data-element name="PersonName" label="Person Name" />
<data-element name="PersonGivenName" label="First Name" />
<data-element name="PersonSurName" label="Sur Name" />
<data-element name="PersonMiddleName" label="Middle Name" />
<data-element name="Address" label="Address" />
<data-element name="LocationStreetFull" label="Street" />
<data-element name="LocationCityName" label="City" />
<data-element name="LocationStateName" label="County" />
<data-element name="LocationCountryName" label="Country" />
<data-element name="LocationPostalID" label="Postal Code" />
</country>
</label-lookup>
</xf:instance>
</xf:model>
</head>
<body>
<p>Demonstration of Dynamic Labels</p>
<xf:select1 bind="country" incremental="true">
<xf:label>Country: </xf:label>
<xf:item>
<xf:label>USA</xf:label>
<xf:value>usa</xf:value>
</xf:item>
<xf:item>
<xf:label>Canada</xf:label>
<xf:value>canada</xf:value>
</xf:item>
<xf:item>
<xf:label>UK</xf:label>
<xf:value>uk</xf:value>
</xf:item>
</xf:select1>
<xf:repeat nodeset="*">
<xf:group ref=".">
<!-- get the label for the group of elements -->
<xf:label class="group-label">
<xf:output value="concat(instance('label-lookup')/country[country-id=instance('selected-country')/country-id]/data-element[string(@name)=string(name(current()))]/@label,':')" />
</xf:label>
<xf:repeat nodeset="*">
<xf:input ref=".">
<xf:label>
<xf:output value="concat(instance('label-lookup')/country[country-id=instance('selected-country')/country-id]/data-element[string(@name)=string(name(current()))]/@label,':')" />
</xf:label>
</xf:input>
</xf:repeat>
</xf:group>
</xf:repeat>
<!-- debug
<xf:output bind="country">
<xf:label>Country id:</xf:label>
</xf:output>
-->
</body>
</html>
Discussion
[edit | edit source]This example shows a nice clean elegant way to iterate over elements in a instance for groups and elements. The structure is:
<xf:repeat nodeset="*"> <!-- match the first level in the instance with groups-->
<xf:group ref=".">
<xf:repeat nodeset="*"> <!-- match the second level in the instance with inputs -->
<xf:input ref=".">
</xf:repeat>
</xf:group>
</xf:repeat>
This examples shows how the output tag can be buried inside the input labels.
<xf:input ref="">
<xf:label>
<xf:output value=""/>
</xf:label>
</xf:input>
Credits
[edit | edit source]This example was originally inspired by Kurt Cagle.
Suggesting Items
Motivation
[edit | edit source]You have a text field that the users types text into. You want to show a list of possible suggested items as the user types. This feature is also known as autocomplete.
Method
[edit | edit source]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) > 1"/>
This program depends on a server-side REST web service that you pass in a single parameter "prefix" such as the following that returns recipe ingredients that begin with ba:
http://www.cems.uwe.ac.uk/xmlwiki/XForms/suggest-ingredient.xq?prefix=ba
This program returns an XML file that is restricted to the suggested ingredients that begin with the prefix passed to the XQuery web service:
<suggestions>
<tc>Ba</tc>
<ingredient>Baking powder</ingredient>
<ingredient>Bananas</ingredient>
<ingredient>Barbecue Sauce</ingredient>
<ingredient>Barley</ingredient>
<ingredient>Barley, malt</ingredient>
<ingredient>Basil</ingredient>
<ingredient>Bass</ingredient>
<ingredient>Bay leaves</ingredient>
</suggestions>
Screen Image
[edit | edit source]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.
Link to XForms Application
[edit | edit source]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:
Sample Program
[edit | edit source]<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) > 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="&"
ref="instance('suggest-query')"
replace="instance" instance="suggest-results">
<xf:action ev:event="xforms-submit">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]"
value="concat('getting suggestions for: ', instance('suggest-query')/prefix)"/>
</xf:action>
</xf:submission>
<!-- this is where we put the logging events -->
<xf:instance id="log">
<data xmlns="">
<event/>
</data>
</xf:instance>
<!-- put the cursor in the first field when the form becomes ready -->
<xf:action ev:event="xforms-ready">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'xforms-ready'"/>
<xf:setfocus control="field-1"/>
</xf:action>
</xf:model>
</head>
<body>
<h3>Suggest Event Test</h3>
<xf:input ref="instance('my-form')/element[1]" incremental="true" id="field-1">
<xf:label>Term 1:</xf:label>
<xf:action ev:event="DOMFocusIn">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Focus into input 1'"/>
</xf:action>
<xf:action ev:event="xforms-value-changed">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Value changed in input 1'"/>
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[1]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Out of input 1'"/>
<xf:setvalue ref="instance('selected-word')/calling-element" value="'1'"/>
</xf:action>
</xf:input>
<br/>
<br/>
<xf:input ref="instance('my-form')/element[2]" incremental="true" id="field-2">
<xf:label>Term 2:</xf:label>
<xf:action ev:event="DOMFocusIn">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'FocusIn input 2'"/>
</xf:action>
<xf:action ev:event="xforms-value-changed">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Value changed in input 2'"/>
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[2]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'FocusOut input 2'"/>
<xf:setvalue ref="instance('selected-word')/calling-element" value="2"/>
</xf:action>
</xf:input>
<br/>
<br/>
<xf:input ref="instance('my-form')/element[3]" incremental="true" id="field-3">
<xf:label>Term 3:</xf:label>
<xf:action ev:event="DOMFocusIn">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'FocusIn input 3'"/>
</xf:action>
<xf:action ev:event="xforms-value-changed">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Value changed in input 3'"/>
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[3]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:setvalue ref="instance('selected-word')/calling-element" value="'3'"/>
</xf:action>
</xf:input>
<xf:group ref="instance('conditional-views')/suggest-view">
<div id="suggest">
<span>suggestions:</span>
<xf:repeat id="results-repeat" nodeset="instance('suggest-results')/ingredient">
<xf:trigger>
<xf:label>
<xf:output ref="."/>
</xf:label>
<!-- When the use clicks on suggestion -->
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="concat('Clicked on a suggestion word:',
instance('suggest-results')/word[index('results-repeat')])"/>
<xf:setvalue ref="instance('my-form')/element[number(instance('selected-word')/calling-element)]"
value="instance('suggest-results')/ingredient[index('results-repeat')]"/>
</xf:action>
</xf:trigger>
</xf:repeat>
</div>
</xf:group>
<br/>
<xf:output ref="instance('selected-word')/calling-element"><xf:label>Prior-field: </xf:label></xf:output>
<br/>
<div id="showlog">
<span>
<b>Event Log</b>
</span>
<xf:repeat id="log-repeat" nodeset="instance('log')/event">
<xf:output ref="."/>
</xf:repeat>
</div>
</body>
</html>
Discussion
[edit | edit source]The above example also has several lines of event logging that can be removed in a production application.
As the user is typing and they see a suggestion they like in the suggestion view they will click on the suggested item trigger. When the focus moves out of the field we must keep track of the element that they just left. This is done by the following:
<xf:action ev:event="DOMFocusOut">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Out of input 1'"/>
<xf:setvalue ref="instance('selected-word')/calling-element" value="'1'"/>
</xf:action>
This example attempts to reuse the selection functions for many elements. To do this we have to get the items selected into the right field. In this example we just set an integer value for the element.
Although this works if all your elements have the same element name you will have to replace the last setvalue with an equivalent string expression if you have many complex items in a form that need suggested values.
Setting the Field Value
[edit | edit source]The following action is used when the use clicks on suggestion:
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]"
value="concat('Clicked on a suggestion word:', instance('suggest-results')/word[index('results-repeat')])"/>
<xf:setvalue ref="instance('my-form')/element[number(instance('selected-word')/calling-element)]"
value="instance('suggest-results')/word[index('results-repeat')]"/>
</xf:action>
The first two values are only for logging. The last setvalue sets the field of the element that has the calling-element value. So for the second element the value would be instance('my-form')/element[2].
Sample XQuery
[edit | edit source]As an example XQuery, we have a collection of "Term" elements with "TermName" subelements. The following XQuery is use for our server side script. If you use eXist just place it in the same collection as the form and call it "suggest-item.xq"
xquery version "1.0";
declare namespace exist="http://exist.sourceforge.net/NS/exist";
declare option exist:serialize "method=xml media-type=text/xml indent=yes";
let $collection-path := '/db/mdr/glossaries/data'
let $search-str := request:get-parameter('prefix', '')
return
<suggestions>{
for $term in collection($collection-path)/Term[starts-with(TermName/text(),$search-str)]
return <item>{$term/TermName/text()}</item>
}</suggestions>
Link to Non-logging XForms Application
[edit | edit source]Load Non-logging XForms Application
Version with no logging
[edit | edit source]<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) > 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="&"
ref="instance('suggest-query')"
replace="instance" instance="suggest-results">
</xf:submission>
<!-- this is where we put the logging events -->
<xf:instance id="log">
<data xmlns="">
<event/>
</data>
</xf:instance>
<!-- put the cursor in the first field when the form becomes ready -->
<xf:action ev:event="xforms-ready">
<xf:setfocus control="field-1"/>
</xf:action>
</xf:model>
</head>
<body>
<h3>Suggest Event Test</h3>
<xf:input ref="instance('my-form')/element[1]" incremental="true" id="field-1">
<xf:label>Term 1:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[1]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:setvalue ref="instance('selected-word')/calling-element" value="'1'"/>
</xf:action>
</xf:input>
<br/>
<br/>
<xf:input ref="instance('my-form')/element[2]" incremental="true" id="field-2">
<xf:label>Term 2:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[2]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:setvalue ref="instance('selected-word')/calling-element" value="2"/>
</xf:action>
</xf:input>
<br/>
<br/>
<xf:input ref="instance('my-form')/element[3]" incremental="true" id="field-3">
<xf:label>Term 3:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('my-form')/element[3]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:setvalue ref="instance('selected-word')/calling-element" value="'3'"/>
</xf:action>
</xf:input>
<xf:group ref="instance('conditional-views')/suggest-view">
<div id="suggest">
<span>suggestions:</span>
<xf:repeat id="results-repeat" nodeset="instance('suggest-results')/ingredient">
<xf:trigger>
<xf:label>
<xf:output ref="."/>
</xf:label>
<!-- When the use clicks on suggestion -->
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="concat('Clicked on a suggestion word:', instance('suggest-results')/word[index('results-repeat')])"/>
<xf:setvalue ref="instance('my-form')/element[number(instance('selected-word')/calling-element)]"
value="instance('suggest-results')/ingredient[index('results-repeat')]"/>
</xf:action>
</xf:trigger>
</xf:repeat>
</div>
</xf:group>
</body>
</html>
Using Minimal Trigger Appearance
[edit | edit source]If you do not like the appearance of the button in the trigger you can add the appearance="minimal" attribute to the trigger element.
The following CSS will reverse the background and font colors when the user hovers over the trigger:
.suggestion:hover {
background-color: blue;
color: white;
padding: 3px;
font-size: 10pt;
}
Preventing Null Searches
[edit | edit source]XForms 1.1 added the conditional event attribute. You can use this to only request an suggestion from the server if the element is at least one character long.
<xf:action ev:event="xforms-value-changed" if="string-length(instance('save-data')/element[1]) gt 0">
<xf:setvalue ref="instance('suggest-query')/prefix" value="instance('save-data')/element[1]"/>
<xf:send submission="get-suggestions"/>
</xf:action>
Discussion
[edit | edit source]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
Dynamic Selection Lists
Motivation
[edit | edit source]You want that the content of a selection list to depend on the value another selection list. This is also known as "Cascading Selection".
Method
[edit | edit source]We have two instances in a model. The first instance populates the first select1 list. The second select1 uses an xf:itemset to only select the relevant items from the second instance. In effect we are adding a "where" clause to the list of items selected in the second list.
The presented form shows an example where the user can select a season (Spring, Summer,...) and in a second select the user will only be able to select from the relevant month in that season.
We also will automatically set the month to null when the season selection changes to make sure our pairing is always valid.
The example had been tested with Firefox 2.0.0.12 and the Mozilla XForms add on 0.8.4 as well as on FireFox 3.0.
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]Load Example XForms Application
Note that the initial values of the selections are set in the instance values.
Sample Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Test conditional selection lists</title>
<xf:model>
<xf:instance id="selected-values" xmlns="">
<data>
<selected-season>Winter</selected-season>
<selected-month>January</selected-month>
</data>
</xf:instance>
<xf:instance id="seasons" xmlns="">
<root>
<item name="Spring"/>
<item name="Summer"/>
<item name="Autumn"/>
<item name="Winter"/>
</root>
</xf:instance>
<xf:instance id="months" xmlns="">
<root>
<item name="January" season="Winter"/>
<item name="February" season="Winter"/>
<item name="March" season="Spring"/>
<item name="April" season="Spring"/>
<item name="May" season="Spring"/>
<item name="June" season="Summer"/>
<item name="July" season="Summer"/>
<item name="August" season="Summer"/>
<item name="September" season="Autumn"/>
<item name="October" season="Autumn"/>
<item name="November" season="Autumn"/>
<item name="December" season="Winter"/>
</root>
</xf:instance>
<xf:bind id="selected-season" nodeset="instance('selected-values')/selected-season"/>
</xf:model>
</head>
<body>
<p>Test conditional selection lists -
month selector depends on the current season</p>
<xf:select1 ref="instance('selected-values')/selected-season">
<xf:label>Season:</xf:label>
<xf:itemset nodeset="instance('seasons')/item">
<xf:label ref="@name"/>
<xf:value ref="@name"/>
</xf:itemset>
<!-- As soon as you chance this value we set the month to be blank -->
<xf:action ev:event="xforms-value-changed">
<xf:setvalue ref="instance('selected-values')/selected-month" value="''"/>
</xf:action>
</xf:select1>
<br/>
<xf:select1 ref="instance('selected-values')/selected-month">
<xf:label>Month:</xf:label>
<xf:itemset nodeset="instance('months')/item[@season=instance('selected-values')/selected-season]">
<xf:label ref="@name"/>
<xf:value ref="@name"/>
</xf:itemset>
</xf:select1>
<br/>
<xf:output ref="instance('selected-values')/selected-season">
<xf:label>selected-season: </xf:label>
</xf:output>
<br/>
<xf:output ref="instance('selected-values')/selected-month">
<xf:label>selected-month: </xf:label>
</xf:output>
<h4>Relevant Months using Repeat</h4>
<xf:repeat nodeset="instance('months')/item[@season=instance('selected-values')/selected-season]">
<xf:output ref="@name"/>
</xf:repeat>
</body>
</html>
Updating the Second Select When the First Select Changes
[edit | edit source]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 change 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.
Incremental Model Loading
Motivation
[edit | edit source]You have a large model and you want to incrementally load different portions of the model when they are needed. This is frequently done when you have a multi-part form and each tab needs additional data. Loading only the data for the initial tab keeps your form load times fast and avoids unnecessarily locking shared data resources.
Method
[edit | edit source]We will create a model with three separate instances, one for a list of people, one for a list of places and one for a list of things. The people will automatically be loaded into the form when the form loads. We will create triggers that will incrementally load the other portions of the model when they are needed. Each trigger will use a submission event that does a separate HTTP get to incrementally load data into a separate instance in the model.
Here is the empty place-holder instance in the model for the places and the submission to get the places data.
<xf:instance id="places">
<null/>
</xf:instance>
<xf:submission id="get-places" method="get" action="places.xml"
replace="instance" instance="places"/>
Here is the trigger (button) that gets the new model.
<xf:submit submission="get-places">
<xf:label>Load Places</xf:label>
</xf:submit>
Screen Image
[edit | edit source]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.
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.
Load XForms Application
[edit | edit source]Example with triggers that manually load incremental data: Load XForms Application
Example with tab-selection events that incrementally load data Load XForms Application
Note that in this example the event log shows that the data is only loaded once regardless of how many times the tab is selected.
Avoiding Reloads
[edit | edit source]The following is an example of how to use conditional actions to check if a instance in the model already has its data loaded into the form:
<xf:case id="places-case">
<xf:action ev:event="xforms-select" if="not(instance('places')/place)">
<xf:send submission="get-places"/>
</xf:action>
<h2>Places</h2>
</xf:case>
The if attribute of the xf:action checks to see if there is at least one place in the places instance. If there is not at least one "place" the submission event is fired.
Sample Code
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Incremental Model Loading</title>
<style type="text/css">body {font-family: Helvetica, Arial, sans-serif;</style>
<xf:model>
<!-- unconditionally loaded when the form loads -->
<xf:instance id="people" src="people.xml">
<null/>
</xf:instance>
<xf:instance id="places">
<null/>
</xf:instance>
<xf:submission id="get-places" method="get" action="places.xml"
replace="instance" instance="places"/>
<xf:instance id="things">
<null/>
</xf:instance>
<xf:submission id="get-things" method="get" action="things.xml"
instance="things" replace="instance"/>
</xf:model>
</head>
<body>
<h1>Incremental Model Loading</h1>
<p>Not all parts of the model need to be loaded into a form when it is first loaded. For
large models, different sections can be loaded as they are needed.</p>
<h2>People</h2>
<xf:group ref="instance('people')">
<xf:repeat nodeset="person">
<xf:output ref="name"/><br/>
</xf:repeat>
</xf:group>
<h2>Places</h2>
<xf:group ref="instance('places')">
<xf:repeat nodeset="place">
<xf:output ref="name"/><br/>
</xf:repeat>
<xf:submit submission="get-places">
<xf:label>Load Places</xf:label>
</xf:submit>
</xf:group>
<h2>Things</h2>
<xf:group ref="instance('things')">
<xf:repeat nodeset="item">
<xf:output ref="name"/><br/>
</xf:repeat>
<xf:submit submission="get-things">
<xf:label>Load Things</xf:label>
</xf:submit>
</xf:group>
</body>
</html>
XML Instance Samples
[edit | edit source][people.xml] [places.xml] [things.xml]
Dynamic Labels in Local language
Motivation
[edit | edit source]Sometimes you may want to change the label dynamically from one language to another language without loading the form. In the given example, you can choose the language from the select1 control option.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>e-District - Regd Form</title>
<!--<link href="edistrict.css" rel="stylesheet"/>-->
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
BODY
{
font-family: Times New Roman,Times,serif;
font-size: 12pt;
font-style: normal;
font-weight:normal;
font-variant: normal;
text-align: left;
word-spacing: normal;
letter-spacing: normal;
/*background-color: transparent;*/
background-image: url(Desktop/tour_xforms/NIC_Logo.gif); background-repeat: no-repeat;
background-position: right top;
line-height:20pt;
}
xf|input, xf|secret {
display: table-row;
}
xf|value {
text-align: left;
}
div.content div.tab-box {
position: absolute;
width: 120px;
}
div{line-height:20pt;}
h3 {text-align: center;}
h4 {color:maroon;text-decoration:underline;}
div.formbody
{
margin-left:2in;
margin-right:0.5in;
width:8.5in;
}
xf|input {display: table-row;text-align:left;}
xf|input > xf|label {display: table-cell; width:160pt; font-weight:bold;text-align:left;}
xf|input .xf-value {width: 100pt;font-size:10pt;}
xf|secret { display: table-row;text-align:left;}
xf|secret > xf|label { display: table-cell; width:160pt; font-weight:bold;text-align:left;}
xf|secret .xf-value {width: 100pt;font-size:10pt;}
xf|output { display: table-row;text-align:left;}
xf|output > xf|label { display: table-cell; width:160pt; font-weight:bold;text-align:left;}
xf|output .xf-value {width: 100pt;font-size:11pt;font-weight:bold;color:blue;text-align:left;}
xf|select1 { display: table-row;text-align:left;}
xf|select1 > xf|label { display: table-cell; width:160pt; font-weight:bold;text-align:left;}
xf|select1 .xf-value {max-width: 100pt;font-size:10pt;}
</style>
<xf:model id="model1">
<xf:instance id="Regd_Form" xmlns="">
<form CAN="" xmlns="">
<name></name>
<DOB></DOB>
<address></address>
<loginId></loginId>
<mobile></mobile>
<phone></phone>
<email></email>
<password></password>
<repeat_pass></repeat_pass>
</form>
</xf:instance>
<xf:instance id="slanguage1" xmlns="">
<language xmlns="">
<lang>English</lang>
<lang_list><item>English</item></lang_list>
<lang_list><item>தமிழ்</item></lang_list>
<lang_list><item>हिन्दी</item></lang_list>
</language>
</xf:instance>
<xf:instance id="slanguage" xmlns="">
<language xmlns="">
<lang name="English" rname="Registration Form" smessage="Registration Completed Successfully"
emessage="Error Occurred .. Pls Check the Entered Details" sbutton="Save" cbutton="Reset" e1msg="Wrong Password!Please Re-enter">
<name>Applicant Name</name>
<DOB>Date of Birth</DOB>
<address>Address</address>
<loginId>Desired Login ID</loginId>
<mobile>Mobile No</mobile>
<phone>Phone No</phone>
<email>E-mail ID</email>
<password>Password</password>
<repeat_pass>Re-Enter Password</repeat_pass>
</lang>
<lang name="தமிழ்" rname="பதிவு படிவம்" smessage="பதிவு சேமிக்கப்பட்டது"
emessage="தவறு! விபரங்களை சரிப்பார்க்கவும்" sbutton="சேமி" cbutton="மீளமை" e1msg="கடவுச்சொல் தவறு!மீண்டும் உறுதிப்படுத்துக">
<name>விண்ணப்பதாரர் பெயர்</name>
<DOB>பிறந்த தேதி</DOB>
<address>முகவரி</address>
<loginId>விருப்பப்படும் நுழைவு பெயர்</loginId>
<mobile>கைத் தொலைபேசி எண் </mobile>
<phone>தொலைபேசி எண்</phone>
<email>மின்னஞ்சல் முகவரி</email>
<password>கடவுச்சொல்</password>
<repeat_pass>கடவுச்சொல் உறுதிப் படுத்து</repeat_pass>
</lang>
<lang name="हिन्दी" rname="पंजीकरण फार्म" smessage="पंजीकरण सफलतापूर्वक पूरा"
emessage="त्रुटि हुई .. Pls दर्ज विवरण की जाँच करें" sbutton="Save" cbutton="Reset" e1msg="पासवर्ड गलत! फिर से दर्ज करें">
<name>आवेदक का नाम</name>
<DOB>जन्म तिथि</DOB>
<address>पता</address>
<loginId>वांछित लॉगिन आईडी</loginId>
<mobile>मोबाइल नंo</mobile>
<phone>फोन नंo</phone>
<email>ई - मेल आईडी</email>
<password>पासवर्ड</password>
<repeat_pass>पुनः पासवर्ड दर्ज करिए</repeat_pass>
</lang>
</language>
</xf:instance>
<xf:action ev:event="xforms-ready">
<xf:setvalue ref="DOB" value="substring(now(),1,10)"/>
</xf:action>
<xf:bind nodeset="instance('Regd_Form')/DOB" type="xs:date" required="true()"/>
<xf:submission id="submit" method="put" action="result.xml">
<xf:action ev:event="xforms-submit-done">
<xf:message level="modal"><xf:output ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@smessage"></xf:output> ...</xf:message>
</xf:action>
<xf:message level="modal" ev:event="xforms-submit-error"><xf:output ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@emessage"></xf:output></xf:message>
</xf:submission>
</xf:model>
</head>
<body bgcolor="#ACBCD8">
<div id="img">
<img src="img.png" width="1027" />
</div><br/>
<div id="formbody" style="width:10.7in;">
<div class="content">
</div>
<center>
<xf:select1 ref="instance('slanguage1')/lang">
<xf:label>Select Language</xf:label>
<xf:itemset nodeset="instance('slanguage1')/lang_list">
<xf:label ref="item"/>
<xf:value ref="item"/>
</xf:itemset>
</xf:select1><br/>
<fieldset style="width: 700px;border:solid 1pt black" >
<h3><xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@rname"></xf:label></h3><br/>
<xf:input ref="instance('Regd_Form')/name">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/name">:</xf:label>
</xf:input>
<xf:input ref="instance('Regd_Form')/DOB">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/DOB">:</xf:label>
</xf:input>
<xf:input ref="instance('Regd_Form')/address">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/address"> :</xf:label>
</xf:input>
<xf:input ref="instance('Regd_Form')/loginId">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/loginId"> :</xf:label>
</xf:input>
<xf:input ref="instance('Regd_Form')/mobile">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/mobile">:</xf:label>
</xf:input>
<xf:input ref="instance('Regd_Form')/phone">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/phone"> :</xf:label>
</xf:input>
<xf:input ref="instance('Regd_Form')/email">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/email"> :</xf:label>
</xf:input>
<xf:secret ref="instance('Regd_Form')/password">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/password"> :</xf:label>
<!--<xf:alert level="modal">கடவுச்சொல் 3 முதல் 7 எழுத்து மட்டுமே</xf:alert>-->
</xf:secret>
<xf:secret ref="instance('Regd_Form')/repeat_pass">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/repeat_pass"> :</xf:label>
<xf:action ev:event="DOMFocusOut" if="instance('Regd_Form')/repeat_pass != instance('Regd_Form')/password">
<xf:setvalue ref="instance('Regd_Form')/repeat_pass" value="''"/>
<xf:message level="modal">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@e1msg"></xf:label></xf:message>
</xf:action>
</xf:secret><br/>
<xf:submit submission="submit">
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@sbutton"></xf:label>
</xf:submit>
<xf:trigger>
<xf:label ref="instance('slanguage')/lang[@name=instance('slanguage1')/lang]/@cbutton"></xf:label>
<xf:reset ev:event="DOMActivate" target="model1"/>
</xf:trigger>
</fieldset>
</center><br/>
</div>
</body>
</html>
Credits
[edit | edit source]This example was originally inspired by Kurt Cagle.
Search Form
Motivation
[edit | edit source]You want to create a search form that uses a single input text field and submits a search request to a search service on a remote web server.
Discussion
[edit | edit source]We are all familiar with the simple front end to search engines like Google that display a simple search field. There are two simple features we will demonstrate in the first version. 1) The input cursor will be positioned in the search field when the form loads. When you press the "Enter" key the search will automatically be executed.
We will also discuss a way to have a single form display both simple search and complex search functions.
Method
[edit | edit source]We will first create a simple search input field and give it an id of "search-field". We will also add an action to the input that will fire off the submission when the Enter key is pressed.
<xf:input ref="q" id="search-field">
<xf:label>Search string:</xf:label>
<xf:action ev:event="DOMActivate">
<xf:send submission="search"/>
</xf:action>
</xf:input>
In this example, q is a reference to the query string we will be sending to the remote server.
From the prior example we learned that you can have the cursor automatically positioned in the search field when the form loads by adding the following action added to your model:
<xf:model>
...
<xf:action ev:event="xforms-ready">
<xf:setfocus control="search-field"/>
</xf:action>
...
</xf:model>
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]In this example we will create a simple front end to Google's search engine. The format of the REST API for the Google search engine is the following:
http://www.google.com/search?hl=en&q=XForms
In this REST query the parameters are:
- hl = language (en for English)
- q = search query string
We can create an instance that has these parameters in our model:
<xf:instance xmlns="">
<data>
<hl>en</hl>
<q></q>
</data>
</xf:instance>
Full Program Listing
[edit | edit source]<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="&"/>
<!-- put the cursor in the first field when the form becomes ready -->
<xf:action ev:event="xforms-ready">
<xf:setfocus control="search-field"/>
</xf:action>
</xf:model>
</head>
<body>
<h1>Google Search Example</h1>
<xf:input ref="instance('search-params')/q" id="search-field">
<xf:label>Search string:</xf:label>
<xf:action ev:event="DOMActivate">
<xf:send submission="search-google"/>
</xf:action>
</xf:input>
<xf:submit submission="search-google">
<xf:label>Search</xf:label>
</xf:submit>
</body>
</html>
Discussion
[edit | edit source]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.
Search with Load
Motivation
[edit | edit source]You want to build a web form that does a search using the xf:load element. This allows you to rewrite the URL to the search application.
Source Code
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events" >
<title>Example of XForms Search with xf:load</title>
<style type="text/css">
body {font-family: Helvetica, sans-serif}
</style>
<xf:model>
<xf:instance xmlns="" id="search-params">
<data>
<url>http://www.example.com/search?q=</url>
<q></q>
</data>
</xf:instance>
<!-- put the cursor in the first field when the form becomes ready -->
<xf:action ev:event="xforms-ready">
<xf:setfocus control="search-field"/>
</xf:action>
</xf:model>
<body>
<h1>Example of XForms Search with xf:load</h1>
<xf:input ref="q" id="search-field" incremental="true">
<xf:label>Enter search string:</xf:label>
<xf:action ev:event="DOMActivate">
<xf:load show="replace">
<xf:resource value="concat(url, q)"/>
</xf:load>
</xf:action>
</xf:input>
<xf:trigger>
<xf:label>Execute Search</xf:label>
<xf:action ev:event="DOMActivate">
<xf:load show="replace">
<xf:resource value="concat(url, q)"/>
</xf:load>
</xf:action>
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]Note that you must use the xf:value attribute of the resource element.
Advanced Search
Motivation
[edit | edit source]You want a simple search function and a separate advanced search options tab.
Source Code
[edit | edit source]<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="&" />
<xf:submission id="adv-search-google" method="get" action="http://www.google.com/search"
replace="all" ref="instance('adv-output-input-params')" separator="&" />
<!-- put the cursor in the first field when the form becomes ready -->
<xf:action ev:event="xforms-ready">
<xf:setfocus control="search-field" />
</xf:action>
</xf:model>
<body>
<h1>Google Search Example</h1>
<div id="horiz-tab-menu">
<xf:trigger appearance="minimal" class="tab">
<xf:label>Simple</xf:label>
<xf:toggle case="simple-search" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger appearance="minimal" class="tab">
<xf:label>Complex</xf:label>
<xf:toggle case="advanced-search" ev:event="DOMActivate" />
</xf:trigger>
</div>
<xf:switch>
<xf:case id="simple-search">
<xf:input ref="instance('search-params')/q" id="search-field">
<xf:label>Search string:</xf:label>
<xf:action ev:event="DOMActivate">
<xf:send submission="search-google" />
</xf:action>
</xf:input>
<xf:submit submission="search-google">
<xf:label>Search</xf:label>
</xf:submit>
</xf:case>
<xf:case id="advanced-search">
<xf:input ref="instance('adv-search-input-params')/q" id="adv-search-field">
<xf:label>Search string:</xf:label>
<xf:action ev:event="DOMActivate">
<xf:send submission="adv-search-google" />
</xf:action>
</xf:input>
<br />
<xf:input ref="instance('adv-search-input-params')/site" id="site-field">
<xf:label>Site URL:</xf:label>
<xf:action ev:event="DOMActivate">
<xf:send submission="adv-search-google" />
</xf:action>
</xf:input>
<br />
<xf:submit submission="adv-search-google">
<xf:label>Search</xf:label>
</xf:submit>
</xf:case>
</xf:switch>
</body>
</html>
Discussion
[edit | edit source]
Date Range Search
Motivation
[edit | edit source]You want to limit search results based on one or more dates within items.
Method
[edit | edit source]We will create a XForms application that will have two calendar selectors. We can use the built-in calendar selector or allow users to select the year, month, day values separately.
Month Code Table
[edit | edit source]<code-table>
<code-table-name>date-month-code</code-table-name>
<description>A list of all the month codes for doing searchs.</description>
<items>
<item>
<label>January</label>
<numeric-id>1</numeric-id>
<abbreviation>Jan</abbreviation>
<value>january</value>
</item>
<item>
<label>February</label>
<numeric-id>2</numeric-id>
<abbreviation>Feb</abbreviation>
<value>february</value>
</item>
<item>
<label>March</label>
<numeric-id>3</numeric-id>
<abbreviation>Mar</abbreviation>
<value>march</value>
</item>
<item>
<label>April</label>
<numeric-id>4</numeric-id>
<abbreviation>Apr</abbreviation>
<value>april</value>
</item>
<item>
<label>May</label>
<numeric-id>5</numeric-id>
<abbreviation>May</abbreviation>
<value>may</value>
</item>
<item>
<label>June</label>
<numeric-id>6</numeric-id>
<abbreviation>Jun</abbreviation>
<value>june</value>
</item>
<item>
<label>July</label>
<numeric-id>7</numeric-id>
<abbreviation>Jul</abbreviation>
<value>july</value>
</item>
<item>
<label>August</label>
<numeric-id>8</numeric-id>
<abbreviation>Aug</abbreviation>
<value>august</value>
</item>
<item>
<label>September</label>
<numeric-id>9</numeric-id>
<abbreviation>Sep</abbreviation>
<value>september</value>
</item>
<item>
<label>October</label>
<numeric-id>10</numeric-id>
<abbreviation>Oct</abbreviation>
<value>october</value>
</item>
<item>
<label>November</label>
<numeric-id>11</numeric-id>
<abbreviation>Nov</abbreviation>
<value>november</value>
</item>
<item>
<label>December</label>
<numeric-id>12</numeric-id>
<abbreviation>Dec</abbreviation>
<value>december</value>
</item>
</items>
</code-table>
Search flickr
Motivation
[edit | edit source]Many sites give you a simple way of using a URL to perform a search. REST (Representational State Transfer) is a structured way to access data on the web without having to use a web service. This example program uses an XForm submission using the Flickr REST service.
Warnings
[edit | edit source]To run this application you MUST enable XForms to submit data to other domains. In FireFox this is done by adding the domains to your trusted list. This can be done by going to the FireFox "Tools" menu, selecting Preferences, selecting the "Content" tab, and adding the sites to your XForms white listed sites. In this case the trusted domain is "flickr.com"
Screen Image
[edit | edit source]Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]<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="&"
replace="instance" instance="inst-rs">
<xf:toggle case="case-busy" ev:event="xforms-submit" />
<xf:toggle case="case-submit-error" ev:event="xforms-submit-error" />
<xf:toggle case="case-done" ev:event="xforms-submit-done" />
</xf:submission>
<!-- Used to hold image size -->
<xf:instance id="inst-control" xmlns="">
<instanceData>
<size>s</size>
</instanceData>
</xf:instance>
</xf:model>
<!--Mozilla XForms Custom Control-->
<bindings id="xformsBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="output-image"
extends="chrome://xforms/content/xforms.xml#xformswidget-base">
<content>
<html:div>
<html:img anonid="content" style="float: left; margin-right: 5px;"/>
</html:div>
</content>
<implementation implements="nsIXFormsUIWidget">
<method name="refresh">
<body>
var img = document.getAnonymousElementByAttribute(this, "anonid", "content");
img.setAttribute("src", this.stringValue);
return true;
</body>
</method>
</implementation>
</binding>
</bindings>
<!-- Bind the custom control to output with class="image" -->
<style type="text/css">
@namespace xf url(http://www.w3.org/2002/xforms);
xf|output.image {
-moz-binding: url('#output-image');
}
</style>
</head>
<!-- BODY -->
<body>
<xf:group id="main-body">
<xf:input ref="tags">
<xf:label>Search for a tag (f.x. "suzuki"):</xf:label>
</xf:input>
<xf:submit submission="sub-flickr">
<xf:label>Find</xf:label>
</xf:submit>
<xf:select1 ref="instance('inst-control')/size" incremental="true">
<xf:label>Size: </xf:label>
<xf:item>
<xf:label>Small</xf:label>
<xf:value>s</xf:value>
</xf:item>
<xf:item>
<xf:label>Medium</xf:label>
<xf:value>m</xf:value>
</xf:item>
</xf:select1>
<xf:switch>
<xf:case id="case-start"></xf:case>
<xf:case id="case-busy">
<p>Searching...</p>
</xf:case>
<xf:case id="case-submit-error">
<p>Submission error! Did you remember to allow XForms to submit data to other domains?</p>
</xf:case>
<xf:case id="case-done">Done</xf:case>
</xf:switch>
<xf:group ref="instance('inst-rs')">
<xf:output ref="err/@msg"/>
<xf:repeat nodeset="photos/photo">
<xf:output
value="concat(
'http://static.flickr.com/',
@server, '/',
@id, '_',
@secret, '_',
instance('inst-control')/size,
'.jpg'
)"
class="image"
/>
</xf:repeat>
<div style="clear: both;"></div>
</xf:group>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]This example shows how to display a different status message based on the state of a submission using the switch/case/toggle elements.
More to Explore
[edit | edit source]The wikipedia page on REST has a list of public implementations of the REST standards. These should be acessible by most XForms (with the appropriate permissions).
REST API from Amazon S3 [2]
References
[edit | edit source]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].
Web service
Web services can be called directly from an XForms application using the submission
element in the model.
Connecting a web service to an Event
[edit | edit source]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="<b>callWebService</b>">
<...>
</xf:submission>
</xf:model>
</head>
<body>
<xf:submit submission="<b>callWebService</b>">
<xf:label>Press Button to Call a Web Service</xf:label>
</xf:submit>
</body>
</<syntaxhighlight>
== Sample Program ==
The program consists of several parts.
In the model:
# The SOAP submission instance
# The submission
# The SOAP response placeholder
=== SOAP input message ===
Here is an example of the input SOAP message
<pre>
<!-- 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 -->
</pre>
=== Putting the SOAP Results in an Instance ===
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".
<syntaxhighlight lang="xml">
<xf:instance id="results-instance" xmlns="">
<env:Envelope/>
</xf:instance>
<xf:bind id="results-bind" nodeset="instance('results-instance')/env:Envelope"/>
This is just a temporary storage area that the results will be inserted into.
The XForms submission
Statement
[edit | edit source] <xf:submission id="send-to-dor-document-web-service"
action="<nowiki>http://www.example.com/web-service/my-web-service</nowiki>"
method="post"
mediatype="text/xml"
ref="instance('submit-instance')"
replace="instance"
instance="results-instance">
<xf:toggle case="case-busy" ev:event="xforms-submit" />
<xf:toggle case="case-submit-error" ev:event="xforms-submit-error" />
<xf:toggle case="case-done" ev:event="xforms-submit-done" />
</xf:submission>
There are few things to note. The action
attribute is the URL of the connection point of the web service. The operation you call is not included in the URL.
The method (get, put or post) in this case is a post.
Mediatype
[edit | edit source]XForms is a rich application development standard. So by default the HTTP transactions used by XForms use a mediatype for XML application that includes binary files and binary attachments. So by default, XForms sends an HTTP command with the following in it:
mediatype="application/xml"
However most simple web services do not support binary. The mediatype
for ASCII text (without binary) is just:
mediatype="text/xml"
So if you will also be sending binary files you will need to add a mediatype attribute to to your submission:
<xf:submission mediatype="application/xml"...
Debugging Response Documents
[edit | edit source]You can also replace the entire document with the XML result (the option is replace="all") or you can just have it replace an instance.
The last three <toggle> statements are for displaying results.
A style sheet
[edit | edit source]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 Presentation
[edit | edit source]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>
Discussion
[edit | edit source]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.
Stock Quote
Motivation
[edit | edit source]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 Program
[edit | edit source]To be done
Discussion
[edit | edit source]
Search Amazon
Motivation
[edit | edit source]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 Image
[edit | edit source]Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]<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="&"
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="&"
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>
Discussion
[edit | edit source]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="&"
References
[edit | edit source]This program was based on an example provided by formsPlayer [6].
Incremental Find
Motivation
[edit | edit source]You want to show a sample list of search keywords as the user types them into a search field.
Method
[edit | edit source]Sample Code
[edit | edit source]<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&format=json&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>
Acknowledgments
[edit | edit source]This example was created by Alain Couthures of agencexml.com
CKEditor
Motivation
[edit | edit source]You want to be able to add HTML markup to a textarea.
Method
[edit | edit source]We will use the CKEditor JavaScript libraries. This demo was done using version 3.2.
Steps:
- Download the source code from: CKEditor web site.
- Uncompress the zip file on your local file system
- 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:
- ckeditor/CHANGES.html
- ckeditor/_source/plugins/wsc/dialogs/ciframe.html
- ckeditor/_source/plugins/wsc/dialogs/tmpFrameset.html
- ckeditor/plugins/wsc/dialogs/ciframe.html
- ckeditor/plugins/wsc/dialogs/tmpFrameset.html
- 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.
- 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 )
- Add the following line to config.js
- config.HtmlEncodeOutput = 'false';
- Replace the sample_postdata.php with the following sample_postdata.xq
Sample XQuery to Echo Post Data
[edit | edit source]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('<div>', $editor1, '</div>')
(: 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 Systems
[edit | edit source]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
Motivation
[edit | edit source]You want to have a region of your page that changes images when the user selects a button.
Method
[edit | edit source]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 Application
[edit | edit source]Sample Source Code
[edit | edit source]<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>
Discussion
[edit | edit source]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.
Attribution
[edit | edit source]This example was created by Chris Wallace and the University of Western England.
Referencing Items
Motivation
[edit | edit source]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.
Method
[edit | edit source]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 Program
[edit | edit source]<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>
Discussion
[edit | edit source]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.
Deep Copy with Insert Origin
Motivation
[edit | edit source]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.
Method
[edit | edit source]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 Application
[edit | edit source]Source Code
[edit | edit source]<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>
Discussion
[edit | edit source]
A Trigger for Inserting BBcode into a Textarea box
Using Trigger to Add BBcode or Other Text to Input or Textarea Controls
[edit | edit source]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 Application
[edit | edit source]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 Structure
[edit | edit source]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 Program
[edit | edit source] <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"> <!--mozilla specific style-->
@namespace xf url('http://www.w3.org/2002/xforms');
xf|textarea .xf-value{ width:25em; height:20ex; }
</style>
<xf:model>
<xf:instance>
<data xmlns="">
<text/>
</data>
</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><br/>
<xf:textarea id="textArea" ref="//text">
<xf:label>Post:</xf:label>
</xf:textarea>
</body>
</html>
Discussion
[edit | edit source]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"/>
Discussion
[edit | edit source]
Multi-Part Forms
Motivation
[edit | edit source]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.
Method
[edit | edit source]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.
Example
[edit | edit source]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
Motivation
[edit | edit source]You have two lists and you would like to move selected items between the lists. This is typically known as a column chooser.
Method
[edit | edit source]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 Image
[edit | edit source]Link to Working Form
[edit | edit source]Sample List Instances
[edit | edit source] <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 XForms
[edit | edit source]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.
- insert a new item in the list by doing a copy of the selected item to the opposite list
- 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 CSS
[edit | edit source]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;}
Discussion
[edit | edit source]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
Motivation
[edit | edit source]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 Image
[edit | edit source]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.
Link to Working Example
[edit | edit source]Sample Code
[edit | edit source]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 Code
[edit | edit source]<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>
Discussion
[edit | edit source]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.
Credits
[edit | edit source]This example contributed by Ann Kelly.
Horizontal File Tab Menu
Sample Horizontal Tab Menu
[edit | edit source]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 Image
[edit | edit source]You should see a menu that looks similar to this when running under the FireFox browser:
Note that the tab that is selected has the same color of the content.
Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]<?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>
Testing
[edit | edit source]Note that the text under the selected tab changes when you click on the tab.
Discussion
[edit | edit source]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 element
[edit | edit source]Here is an example that uses the CSS-3 target pseudo element:
We could also modify the example to work with XForms.
Using the Non-Standard Attribute Value Templates (AVT)
[edit | edit source]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.
References
[edit | edit source]Kurt Cagle's Article on Tabs on XML Today
Horizontal File Tab Menu Highlighted
Motivation
[edit | edit source]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 element
[edit | edit source]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 Image
[edit | edit source]Sample Program
[edit | edit source]<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>
Discussion
[edit | edit source]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 improvement
[edit | edit source]Although this "hack" works and it does get rid of some commonly occurring JavaScript, it is still lacking in several ways.
- You can only have a single selected tab on a page.
- There is no way to highlight the initial tab without adding the label in the URL
- 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 Examples
[edit | edit source]The following example shows how tab elements can be stored within a model: Kurt Cagle Tab Example
Vertical Menu
Motivation
[edit | edit source]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 Image
[edit | edit source]Sample Program
[edit | edit source]<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>
Discussion
[edit | edit source]This is similar to the horizontal tab menu. It uses the CSS-3 target pseudo element.
References
[edit | edit source]
Storing Tabs in the Model
Motivation
[edit | edit source]You want to dynamically modify your tabs while the form is executing.
Method
[edit | edit source]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 Example
[edit | edit source]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
Acknowledgments
[edit | edit source]This example was posted by Kurt Cagle on XML Today.
Folding Menus
Motivation
[edit | edit source]You want to display a complex list of choices in a tree structure where each branch could be opened and closed.
Sample Program
[edit | edit source]<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('                                                          ',1,3 * count(current()/ancestor::*)), '     ')" />
<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('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id), substring-after(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id)), concat(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id))"
/>
</xf:action>
</xf:trigger>
<xf:output class="outputInline" ref="./@category" />
<xf:repeat nodeset="./item" id="repeatItem">
<xf:output class="outputInline"
value="concat(substring('                                                          ',1,3 * count(current()/ancestor::*)), '     ')" />
<xf:output class="outputInline" ref="./@id">
<xf:label>id: </xf:label>
</xf:output>
<xf:input class="inputInline" ref=".[name() = 'item' or name() = 'file']">
<xf:label>data: </xf:label>
</xf:input>
</xf:repeat>
</xf:repeat>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]There are some interesteing XPath expressions in this example. For example the following counts the number of ancestor nodes of the current node:
count(current()/ancestor::*)
The following gets all of the decendant groups within the instance data:
instance('instanceData')/descendant::group
The following returns a "+" if the nodelist contains the value in the id attribute and a "-" if it does not.
if(contains(instance('foldedNodes')/nodelist, ./@id), '+', '-')
Credits
[edit | edit source]Thanks to Fraser for posting this on the Mozilla XForms developer newsgroup in Oct. of 2007
Tree Menus
Motivation
[edit | edit source]You want to have a menu that allows you to navigate a tree hierarchy of editable items.
Method
[edit | edit source]Source Code
[edit | edit source]<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>Hierarchial Tree Menu</title>
<link href="tree.css" type="text/css" rel="stylesheet"/>
<xf:model id="modelOI">
<xf:instance xmlns="" id="instanceData">
<Data>
<currentLot/>
<currentItem/>
<Lot code="">
<Item code=""/>
<Item code=""/>
</Lot>
<Lot code="">
<Item code=""/>
<Item code=""/>
<Item code=""/>
</Lot>
<Lot code="">
<Item code=""/>
<Item code=""/>
</Lot>
</Data>
</xf:instance>
<xf:bind nodeset="Lot/@code" calculate="position()"/>
<xf:bind nodeset="Lot/Item/@code" calculate="position()"/>
<xf:instance xmlns="" id="instanceTemplate">
<Data>
<Lot code="">
<Item code=""/>
</Lot>
</Data>
</xf:instance>
</xf:model>
</head>
<body>
<div id="divMenu">
<xf:output ref="/Data/currentLot">
<xf:label>current Lot : </xf:label>
</xf:output>
<xf:output ref="/Data/currentItem">
<xf:label>current Item : </xf:label>
</xf:output>
<ul>
<xf:repeat nodeset="/Data/Lot" id="repeatLot">
<li>
<a href="#" id="aLot">
<xf:output ref="@code">
<xf:label>lot </xf:label>
</xf:output>
</a>
<xf:action ev:event="DOMActivate" ev:observer="aLot">
<xf:setvalue ref="/Data/currentLot" value="/Data/Lot[index('repeatLot')]/@code"/>
<xf:setvalue ref="/Data/currentItem" value="'?'"/>
<xf:toggle case="editCode"/>
</xf:action>
<ul>
<xf:repeat nodeset="Item" id="repeatItem">
<li>
<a href="#" id="aItem">
<xf:output ref="@code">
<xf:label>item </xf:label>
</xf:output>
<xf:output ref="."/>
</a>
<xf:action ev:event="DOMActivate" ev:observer="aItem">
<xf:setvalue ref="/Data/currentLot" value="/Data/Lot[index('repeatLot')]/@code"/>
<xf:setvalue ref="/Data/currentItem" value="/Data/Lot[@code=/Data/currentLot]/ Item[position()=index('repeatItem')]/@code"/>
<xf:toggle case="editItem"/>
</xf:action>
</li>
</xf:repeat>
</ul>
</li>
</xf:repeat>
</ul>
<xf:trigger>
<xf:label>Insert Lot at last</xf:label>
<xf:action ev:event="DOMActivate">
<xf:rebuild/>
<xf:recalculate/>
<xf:refresh/>
<xf:insert nodeset="Lot" at="last()" position="after" origin="instance('instanceTemplate')/Lot"/>
<xf:setvalue ref="/Data/currentLot" value="count(/Data/Lot)"/>
<xf:setvalue ref="/Data/currentItem" value="/Data/ Lot[count(/Data/Lot)-1]/Item[last()]/@code + 1"/>
<xf:rebuild/>
<xf:recalculate/>
<xf:refresh/>
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Insert Item at selected Lot</xf:label>
<xf:action ev:event="DOMActivate">
<xf:rebuild/>
<xf:recalculate/>
<xf:refresh/>
<xf:insert nodeset="/Data/Lot[index('repeatLot')]/Item" at="index('repeatItem')" position="after" origin="instance('instanceTemplate')/Lot/Item"/>
<xf:rebuild/>
<xf:recalculate/>
<xf:refresh/>
</xf:action>
</xf:trigger>
</div>
<div class="divEdition">
<xf:switch>
<xf:case id="editCode">
<xf:group ref="/Data/Lot[@code=/Data/currentLot]">
<fieldset>
<legend>
Lot n°<xf:output value="@code"/>
</legend>
<xf:input ref="@code">
<xf:label>code : </xf:label>
</xf:input>
</fieldset>
</xf:group>
</xf:case>
<xf:case id="editItem">
<xf:group ref="/Data/Lot[@code=/Data/currentLot]/Item[@code=/Data/currentItem]">
<fieldset>
<legend>
Item n°<xf:output value="@code"/>
</legend>
<xf:input ref="@code">
<xf:label>item : </xf:label>
</xf:input>
</fieldset>
</xf:group>
</xf:case>
</xf:switch>
</div>
</body>
</html>
CSS
[edit | edit source]#divMenu {
float: left;
width:220px;
margin: 0 20px 0 10px;
}
#divMenu ul {
padding: 0 0 5px 5px;
}
#divMenu li{
color:#000000;
}
#divMenu li .xf-repeat-item {
}
#divMenu .xf-repeat-index {
font-weight: bold;
}
#divEdition {
float: left;
}
Acknowledgments
[edit | edit source]This example was contributed to the Mozilla XForms Newsgroup by Andy Bailey on Apr 24 2008.
Deselect Events
Motivation
[edit | edit source]You want to catch a deselection event when you navigate away from a page.
Sample Code
[edit | edit source]<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>Demo of Deselection Event</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;
}
</style>
<xf:model id="image">
<xf:instance xmlns="" id="image">
<data/>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Deselection Events Demo</h1>
<p>The deselection event will generate a message each time a new tab is selected.</p>
<div id="tab-bar">
<xf:trigger appearance="minimal">
<xf:label>Image Tab</xf:label>
<xf:toggle case="image-tab" ev:event="DOMActivate"/>
</xf:trigger>
<xf:trigger appearance="minimal">
<xf:label>Metadata for Image Tab</xf:label>
<xf:toggle case="metadata-tab" ev:event="DOMActivate"/>
</xf:trigger>
<xf:trigger appearance="minimal">
<xf:label>Rights Tab</xf:label>
<xf:toggle case="rights-tab" ev:event="DOMActivate"/>
</xf:trigger>
</div>
<xf:switch>
<xf:case id="image-tab">
<xf:message level="modal" ev:event="xforms-deselect">Deselecting Image Tab</xf:message>
<h1>Image Tab</h1>
<xf:input>
<xf:label>Alt text:</xf:label>
</xf:input>
<xf:select1 appearance="minimal">
<xf:label>Image Type:</xf:label>
<xf:message level="modal" ev:event="xforms-deselect">select1 deselect</xf:message>
<xf:message level="modal" ev:event="DOMFocusOut">DOM Focus Out</xf:message>
<xf:item>
<xf:label>Photo</xf:label>
<xf:value>Photo</xf:value>
</xf:item>
<xf:item>
<xf:label>Logo</xf:label>
<xf:value>Logo</xf:value>
</xf:item>
<xf:item>
<xf:label>Other</xf:label>
<xf:value>Other</xf:value>
</xf:item>
</xf:select1>
<xf:input>
<xf:label>Caption</xf:label>
</xf:input>
<xf:textarea>
<xf:label>CMS description</xf:label>
</xf:textarea>
</xf:case>
<xf:case id="metadata-tab">
<xf:message level="modal" ev:event="xforms-deselect">Deselecting Metadata Tab</xf:message>
<h1>Metadata Tab</h1>
</xf:case>
<xf:case id="rights-tab">
<xf:message level="modal" ev:event="xforms-deselect">Deselecting Rights Tab</xf:message>
<h1>Metadata Tab</h1>
<xf:label>Rights details</xf:label>
<xf:help>State the rights ownership of this feature.</xf:help>
<xf:input>
<xf:label>Rights owner</xf:label>
<xf:help>
<p class="instructions">'BBC' is set as the default. Only set an owner if
there are particular requirements</p>
</xf:help>
</xf:input>
<xf:select1 appearance="minimal">
<xf:label>Rights status</xf:label>
<xf:item>
<xf:label>Free</xf:label>
<xf:value>free</xf:value>
</xf:item>
<xf:item>
<xf:label>Copyrighted</xf:label>
<xf:value>copyrighted</xf:value>
</xf:item>
</xf:select1>
<xf:textarea>
<xf:label>Rights notes:</xf:label>
</xf:textarea>
</xf:case>
</xf:switch>
</body>
</html>
Discussion
[edit | edit source]
Horizontal File Tab Menu Highlighted With Binding
Motivation
[edit | edit source]This is another approach for a horizontal file tab menu.
Approach: Use a binding with a relevant attribute and the CSS-3 :enabled
and :disabled
pseudo classes
[edit | edit source]This example uses an instance to record which tab is currently selected. In conjunction with a binding with a relevant attribute it is possible to use the CSS-3 :enabled
and :disabled
pseudo classes to highlight the selected tab. The relevant condition is the selected
attribute of a tab. The triggers refer to the instance. If a tab in the instance has a selected
attribute set to "true" the corresponding trigger is "enabled" the other triggers are disabled (and by default not visible). They are made visible in the CSS statement for the disabled triggers.
Two additional lines are needed in the case statements to toggle the selected
attribute in the instance for each tab. The two events "xforms-select" and "xforms-deselect" are used to set the values.
Note: This approach is only tested with Firefox 3.0 and the Mozilla XForms Plugin 0.8.6ff3.
Note that this example is based on the Horizontal File Tab Menu Highlighted example but uses a trigger, menu and events to toggle the tabs instead.
Screen Image
[edit | edit source]Sample XForms Application
[edit | edit source]Sample Program
[edit | edit source]<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>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 {
display: inline;
}
/* style each individual tab */
div.horiz-tabs-menu xf|trigger.tab {
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 (disabled) tabs appear in the background */
div.horiz-tabs-menu xf|trigger.tab:disabled {
/* by default disabled (non relevant) items are not displayed,
so they need to be displayed to be in the background */
display: inline;
border-bottom: none;
background: #999;
}
/* Make the selected (enabled) item or default selection to appear on top */
div.horiz-tabs-menu xf|trigger.tab:enabled {
border-bottom: 0.1em solid #CCC;
background: #CCC;
}
xf|switch xf|case div {
background: #CCC; /* Light gray */
padding: 0.3em; /* Looks better */
}
</style>
<xf:model id="tab-handling">
<xf:instance xmlns="" id="tabs">
<tabs>
<tab title="Tab 1" selected="true"/>
<tab title="Tab 2" selected="false"/>
<tab title="Tab 3" selected="false"/>
</tabs>
</xf:instance>
<xf:bind nodeset="instance('tabs')/tab" relevant="@selected = 'true'" type="xs:boolean"/>
</xf:model>
</head>
<body>
<xf:group model="tab-handling" ref="instance('tabs')">
<div class="horiz-tabs-menu">
<xf:trigger ref="tab[1]" class="tab" appearance="minimal">
<xf:label><xf:output ref="@title"/></xf:label>
<xf:toggle ev:event="DOMActivate" case="case-1"/>
</xf:trigger>
<xf:trigger ref="tab[2]" class="tab" appearance="minimal">
<xf:label><xf:output ref="@title"/></xf:label>
<xf:toggle ev:event="DOMActivate" case="case-2"/>
</xf:trigger>
<xf:trigger ref="tab[3]" class="tab" appearance="minimal">
<xf:label><xf:output ref="@title"/></xf:label>
<xf:toggle ev:event="DOMActivate" case="case-3"/>
</xf:trigger>
</div>
</xf:group>
<xf:switch>
<xf:case id="case-1" selected="true()">
<xf:setvalue model="tab-handling" ev:event="xforms-select"
ref="instance('tabs')/tab[1]/@selected" value="true()"/>
<xf:setvalue model="tab-handling" ev:event="xforms-deselect"
ref="instance('tabs')/tab[1]/@selected" value="false()"/>
<div>
1111111111 1111111111 1111111111
1111111111 1111111111 1111111111
1111111111 1111111111 1111111111
1111111111 1111111111 1111111111
</div>
</xf:case>
<xf:case id="case-2">
<xf:setvalue model="tab-handling" ev:event="xforms-select"
ref="instance('tabs')/tab[2]/@selected" value="true()"/>
<xf:setvalue model="tab-handling" ev:event="xforms-deselect"
ref="instance('tabs')/tab[2]/@selected" value="false()"/>
<div>
2222222222 2222222222 2222222222
2222222222 2222222222 2222222222
2222222222 2222222222 2222222222
2222222222 2222222222 2222222222
</div>
</xf:case>
<xf:case id="case-3">
<xf:setvalue model="tab-handling" ev:event="xforms-select"
ref="instance('tabs')/tab[3]/@selected" value="true()"/>
<xf:setvalue model="tab-handling" ev:event="xforms-deselect"
ref="instance('tabs')/tab[3]/@selected" value="false()"/>
<div>
3333333333 3333333333 3333333333
3333333333 3333333333 3333333333
3333333333 3333333333 3333333333
3333333333 3333333333 3333333333
</div>
</xf:case>
</xf:switch>
</body>
</html>
Discussion
[edit | edit source]The selected file-tab should highlight in a light grey. Setting the selected
attribute of a tab to "true" in the instance, highlights the tab on page load. The corresponding selected attribute of the case should be set accordingly.
Some additional code is needed to simulate the toggeling of the triggers.
A better approach would be to have a build in mechanism doing something similar.
Hierarchical Bookmarks
Motivation
[edit | edit source]We often need to be able to edit groupings of data. This example demonstrates how groupings of records (a section of bookmarks) can be modified as a block. This example uses nested <repeat>
to achieve this.
Screen Image
[edit | edit source]Link to working example
[edit | edit source]Sample Programs
[edit | edit source]Firefox XForms Example
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
.repeat-section-container {width:90%; background:#ccc; margin:auto; margin-bottom:20px; padding:10px 0;}
.sectionLabel, .delete-section {margin:0 0 10px 10px;}
#repeatBookmarks .xf-repeat-index {
background:#faa;
}
xf|label.sectionLabel {
font-size: 20px;
font-weight: bold;
color: blue;
}
.bookmark xf|label {
font-weight: bold;
color: black;
}
.bookmark {
margin-left: 12px;
margin: 5px 5px;
}
/* custom fields widths using FireFox value property */
.bookmark-name .xf-value {width:30ex}
.url .xf-value {width:60ex}
</style>
<title>Editing Hierarchical Bookmarks With Firefox XForms Extension</title>
<xf:model id="bookmarks">
<xf:instance src="bookmarks.xml" id="bookmarks" />
<xf:submission id="update-from-local-file" method="get" action="bookmarks.xml" replace="instance" instance="bookmarks" />
<xf:submission id="save-to-local-file" method="put" action="bookmarks.xml" />
</xf:model>
</head>
<body>
<!-- For each section -->
<xf:repeat nodeset="section" id="repeatSections">
<div class="repeat-section-container">
<xf:input ref="@name">
<xf:label class="sectionLabel">Section: </xf:label>
</xf:input>
<!-- For all bookmarks in this section -->
<xf:repeat nodeset="bookmark" id="repeatBookmarks">
<div class="bookmark">
<xf:input class="bookmark-name" ref="@name">
<xf:label>Name: </xf:label>
</xf:input>
<xf:input class="url" ref="@href">
<xf:label>URL: </xf:label>
</xf:input>
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:delete nodeset="." at="index('repeatBookmarks')" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger>
<xf:label>Insert</xf:label>
<xf:insert nodeset="." at="index('repeatBookmarks')" position="after" ev:event="DOMActivate" />
</xf:trigger>
</div>
</xf:repeat>
<xf:trigger class="delete-section">
<xf:label>Delete Section</xf:label>
<xf:delete nodeset="." at="index('repeatSections')" ev:event="DOMActivate" />
</xf:trigger>
</div>
</xf:repeat>
<xf:trigger id="insertbutton">
<xf:label>Insert bookmark</xf:label>
<xf:insert nodeset="section[index('repeatSections')]/bookmark" at="index('repeatBookmarks')" position="after" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger id="insertsectionbutton">
<xf:label>Insert section</xf:label>
<xf:insert nodeset="section" at="index('repeatSections')" position="after" ev:event="DOMActivate" />
</xf:trigger>
<xf:submit submission="update-from-local-file">
<xf:label>Reload</xf:label>
<xf:hint>Reload from local file</xf:hint>
</xf:submit>
<xf:submit submission="save-to-local-file">
<xf:label>Save</xf:label>
<xf:hint>Save to local file</xf:hint>
</xf:submit>
</body>
</html>
FormFaces Example
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
xf|label.sectionLabel {
font-size: 20px;
font-weight: bold;
color: blue;
}
.bookmark xf|label {
font-weight: bold;
color: black;
}
.bookmark {
margin-left: 12px;
margin: 5px 5px;
}
/* custom fields widths using FireFox value property */
.bookmark-name .xf-value {width:30ex}
.url .xf-value {width:60ex}
</style>
<title>Editing Hierarchical Bookmarks With Firefox XForms Extension</title>
<xf:model id="bookmarks">
<xf:instance src="bookmarks.xml" id="bookmarks" />
<xf:submission id="update-from-local-file" method="get" action="bookmarks.xml" replace="instance" instance="bookmarks" />
<xf:submission id="save-to-local-file" method="put" action="bookmarks.xml" />
</xf:model>
</head>
<body>
<!-- For each section -->
<xf:repeat nodeset="section" id="repeatSections">
<xf:input ref="@name" >
<xf:label class="sectionLabel">Section: </xf:label>
</xf:input>
<!-- For all bookmarks in this section -->
<xf:repeat nodeset="bookmark" id="repeatBookmarks">
<div class="bookmark">
<xf:input class="bookmark-name" ref="@name">
<xf:label>Name: </xf:label>
</xf:input>
<xf:input class="url" ref="@href">
<xf:label>URL: </xf:label>
</xf:input>
</div>
</xf:repeat>
</xf:repeat>
<xf:trigger id="insertbutton">
<xf:label>Insert bookmark</xf:label>
<xf:insert nodeset="section[index('repeatSections')]/bookmark"
at="index('repeatBookmarks')" position="after" ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger id="delete">
<xf:label>Delete bookmark</xf:label>
<xf:delete nodeset="section[index('repeatSections')]/bookmark"
at="index('repeatBookmarks')" ev:event="DOMActivate" />
</xf:trigger>
<br/>
<xf:trigger id="insertsectionbutton">
<xf:label>Insert section</xf:label>
<xf:insert nodeset="section" at="index('repeatSections')" position="after"
ev:event="DOMActivate" />
</xf:trigger>
<xf:trigger id="deletesectionbutton">
<xf:label>Delete section</xf:label>
<xf:delete nodeset="section" at="index('repeatSections')" ev:event="DOMActivate" />
</xf:trigger>
<br/>
<xf:submit submission="update-from-local-file">
<xf:label>Reload</xf:label>
<xf:hint>Reload from local file</xf:hint>
</xf:submit>
<xf:submit submission="save-to-local-file">
<xf:label>Save</xf:label>
<xf:hint>Save to local file</xf:hint>
</xf:submit>
</body>
</html>
Sample bookmarks.xml File
[edit | edit source]This is the file that is read into the instance and updated when save is clicked.
<?xml version="1.0" encoding="UTF-8"?>
<!--bookmarks.xml-->
<bookmarks>
<section name="Book Homepage">
<bookmark href="http://en.wikibooks.org/wiki/XForms" name="XForms Tutorial and Cookbook"></bookmark>
</section>
<section name="Introduction">
<bookmark href="http://en.wikibooks.org/wiki/XForms/Background" name="Background"></bookmark>
<bookmark href="http://en.wikibooks.org/wiki/XForms/Benefits" name="Benefits"></bookmark>
<bookmark href="http://en.wikibooks.org/wiki/XForms/Installing_and_Testing" name="Installing and Testing"></bookmark>
<bookmark href="http://en.wikibooks.org/wiki/XForms/Naming_Conventions" name="Naming Conventions"></bookmark>
</section>
<section name="Beginning Examples">
<bookmark href="http://en.wikibooks.org/wiki/XForms/HelloWorld" name="Hello World"></bookmark>
<bookmark href="http://en.wikibooks.org/wiki/XForms/Message" name="Benefits"></bookmark>
</section>
</bookmarks>
Discussion
[edit | edit source]This example does not have re-ordering.
References
[edit | edit source]This version was inspired by an example program on the w3c web site.
Outline Editor
Motivation
[edit | edit source]Sometimes you want to allow a user to be able to add properties to a list that change the appearance of the item in the list. In this example, the level of indentation is controlled by an attribute in a list called the "level" which is the indentation level in an outline view.
Note: This program was based on an example Kurt Cagle posted on the Mozilla XForms developer news group. This example posted with his permission.
Screen Image
[edit | edit source]Link to working Program
[edit | edit source]Sample Program
[edit | edit source]Here is a sample outline-editor program. If you want to test this, be sure to use the edit view to copy the text. This file includes several tab characters that do not display correctly in the view mode.
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/2007/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xbl="http://www.mozilla.org/xbl">
<head>
<!-- based on example posted by Kurt Cagle on Mozilla XForms Newsgroup in Feb. 2007 -->
<style type="text/css">
#itemEntry .xf-value {
width:250px;
}
#content {
border:inset 2px blue;
width:350px;
height:400px;
overflow-y:auto;
background: silver;
}
</style>
<xf:model id="data_model">
<xf:instance id="document_data" src="item-tree.xml" xmlns=""/>
<xf:bind nodeset="//delete-trigger-enabled" relevant="count(//item) > 1" />
<xf:action ev:event="xforms-ready">
<xf:setfocus control="itemEntry" />
</xf:action>
<xf:action ev:event="addItemEvent">
<xf:insert nodeset="//data//item[position() =
index('list')]" at="index('list')" position="after" />
<xf:setvalue ref="//data//item[position() =
index('list')]" value="" />
<xf:setvalue ref="//data//item[position() =
index('list')]/@level" value="//data//item[position() =
index('list') - 1]/@level" />
<xf:setfocus control="itemEntry" />
</xf:action>
<xf:action ev:event="removeItemEvent">
<xf:delete nodeset="//data//item[position() =
index('list')]" at="index('list')" />
<xf:setindex repeat="list" index="index('list')-1" />
<xf:setfocus control="itemEntry" />
</xf:action>
<xf:action ev:event="promoteItemEvent">
<xf:setvalue ref="//data//item[position() =
index('list')]/@level" value="if(number(.) - 1 < 1,1, number(.) - 1)" />
<xf:setfocus control="itemEntry" />
</xf:action>
<xf:action ev:event="demoteItemEvent">
<xf:setvalue ref="//data//item[position() =
index('list')]/@level" value="if(index('list') != 1,
if (number(.) > //data//item[position() =
index('list')-1]/@level,(//data//item[position() =
index('list')-1]/@level) + 1,number(.) + 1),1)" />
<xf:setfocus control="itemEntry" />
</xf:action>
<xf:submission id="save" method="put" action="item-tree.xml" instance="document_data"/>
</xf:model>
</head>
<body>
<xf:group ref="/container/data">
<div>
<xf:trigger id="addItem">
<xf:label>Add</xf:label>
<xf:action ev:event="DOMActivate">
<xf:dispatch name="addItemEvent" target="data_model" />
</xf:action>
</xf:trigger>
<xf:trigger id="removeItem">
<xf:label>Remove</xf:label>
<xf:action ev:event="DOMActivate">
<xf:dispatch name="removeItemEvent" target="data_model" />
</xf:action>
</xf:trigger>
<xf:trigger id="promote">
<xf:label>Promote <</xf:label>
<xf:action ev:event="DOMActivate">
<xf:dispatch name="promoteItemEvent" target="data_model" />
</xf:action>
</xf:trigger>
<xf:trigger id="demote">
<xf:label>Demote ></xf:label>
<xf:action ev:event="DOMActivate">
<xf:dispatch name="demoteItemEvent" target="data_model" />
</xf:action>
</xf:trigger>
<div id="content">
<xf:repeat nodeset="items/item" id="list">
<div>
<xf:input ref="." id="itemEntry" incremental="true">
<xf:label>
<xf:output value="concat(substring('                  ',
1, 3*(number(@level) - 1)),'* ')" />
</xf:label>
<xf:action ev:event="DOMActivate">
<xf:dispatch name="addItemEvent" target="data_model" />
</xf:action>
</xf:input>
</div>
</xf:repeat>
</div>
</div>
</xf:group>
<xf:submit submission="save">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
Sample Instance File "item-tree.xml"
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<container>
<data>
<items>
<item level="1">none</item>
<item level="2">Fiction</item>
<item level="3">Fantasy</item>
<item level="3">Mystery</item>
<item level="3">Religion</item>
<item level="3">Romance</item>
<item level="3">Science Fiction</item>
<item level="2">Non-Fiction</item>
<item level="3">Cooking</item>
<item level="3">History</item>
<item level="3">Biographies</item>
<item level="3">Computers</item>
<item level="4">Software</item>
<item level="5">XForms Tutorial and Cookbook</item>
<item level="3">Internet</item>
<item level="3">Nature</item>
<item level="3">Science</item>
<item level="1">Electronics</item>
<item level="1">Music</item>
</items>
</data>
</container>
Discussion
[edit | edit source]The structure of this program uses custom events. Note that in the model there are a series of actions, each with their own event name:
<xf: model id="data_model">
...
<xf:action ev:event="addItemEvent">
...
These events are called directly inside of a trigger like this:
<xf:dispatch name="addItemEvent" target="data_model" />
Note that the target attribute is the name of the model that the events are located.
Although actions can be tucked directly into a trigger, sometimes action are more logically grouped with instance data and should be placed directly in the model. This also allows other events need to reuse these actions, so it is a good ideal to put reuseable actions directly in a model
References
[edit | edit source]A version of this program was initially posted by Kurt Cagle on the Mozilla XForms newsgroup.
Read and write with get and put
Motivation
[edit | edit source]Sometimes all you need to do is to put a nice user friendly form that edits a single static XML file. In this case a static file is any file where you know the exact pathname to the file when the form is created and you know that the file name will never change. This is the case when an application has a configuration file in a known location (either absolute or fixed relative to the XForm).
If this is a local file on your hard drive this is very easy to do just by using get and put operations and either absolute path names to the file or relative path names to the directory that the form is located.
XForms also allows a user to read data into a form using a HTTP get and to write data from a file using HTTP put operations using a remote web server. Just make sure you enable put operations on your web server and that the file you are putting is writeable This means you will need to do a chmod +w if it is a UNIX file.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<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>Submission with get and put</title>
<xf:model>
<xf:instance id="data-instance" src="data.xml" xmlns="" />
<xf:submission id="read-from-file" method="get"
action="data.xml" replace="instance" instance="data-instance" />
<xf:submission id="save-to-file" method="put"
action="data.xml" replace="instance" instance="data-instance" />
</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>Elementu 1:</xf:label>
</xf:input>
<br />
<xf:input ref="Element2">
<xf:label>Elementul 2:</xf:label>
</xf:input>
<br />
<xf:input ref="Element3">
<xf:label>Elementuul 3:</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>
Sample data.xml
Instance File
[edit | edit source]The following file is read into memory (from the same folder that the form was executed in) when the form is loaded into the browser. This file is written to the disk when the save button is pressed. The reload button will reload the file into the browser.
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Element1>One</Element1>
<Element2>Two</Element2>
<Element3>Three</Element3>
</Data>
Discussion
[edit | edit source]Note that this form is not applicable when the form data is in a file name that is selected at run time. This is because the src
attribute in instance is not dynamic. You can not use an XPath expression in the src
attribute.
Here is an example of how files could be dynamically loaded in XForms 1.1:
<!-- sample code that could be used in XForms 1.1 -->
<xf:submission id="read-from-file" method="get" replace="instance" instance="data-instance">
<xf:resource value="instance('my-instance')/FileNameSetByUpload"/>
</xf:submission>
Note that if this was the case, any form from a nefarious web site might be able to look for a known files or suspicious such as my-passwords.doc and upload them without your consent. This restriction may be eased if the "resource" attribute (part of the XForms 1.1 draft) gets implemented.
References
[edit | edit source]XForms 1.1 standard on submit resource - This allows the resource path to be dynamically created based on instance data.
Saving Intermediate Form Data
NOTE – this page is in development
[edit | edit source]Saving Intermediate Form Data
[edit | edit source]This example will show you how to save intermediate form data to a local disk.
Motivation
[edit | edit source]Sometimes long forms take a while to fill out. You would like to allow users to fill out part of a form, log off, and resume their form when they return. Sometimes this intermediate data can be used as a default template for fields that are re-entered frequently by form users.
Cross Domain Posting A Security Concern
[edit | edit source]By default, XForms will not allow a form to be served from one domain and then access another domain without the user being warned. This could allow a nefarious form to access local files without authorization.
This is reflected in the fact that the "src" tag in the instance can only reference a hard-coded static string. You can not load a local file into an instance if the form was loaded from a web server.
Note that you can read and write a local file on the local file system with an XForms application that supports the file: type such as FireFox. But the forms must have this path statically coded into the XForms instance src attribute.
Steps
[edit | edit source]Step 1: Save to Client
[edit | edit source]Save instance data:
<xf:submission id="save-instance-to-client"
method="put"
action="file://C:/tmp/xforms/my-data.xml"
replace="instance"
instance="my-instance"
/>
Step 2: Read From Client
[edit | edit source]Save instance data:
<xf:submission id="read-instance-from-client"
method="get"
action="file://C:/tmp/xforms/my-data.xml"
replace="instance"
instance="my-instance"
/>
Note that to find the file you can use the <xf:upload> control:
<xf:upload ref="FilePath">
<xf:mediatype>text/xml</xf:mediatype>
</xf:upload>
The value of the action
attribute in both xf:submission
s save-instance-to-file
and read-instance-from-file
should be a variable: action="file://C:/tmp/xforms/my-data.xml"
should be automatically changed to FilePath
value.
Solution
[edit | edit source]To get this to work you have to deal with the security concerns...
Notes
[edit | edit source]There was a reference to using the chrome:// prefix not the file:// prefix on one posting..but no example was given. There was also some discussion of saving to a cookie using cookie://
References
[edit | edit source]
Tri-Document Loading
Motivation
[edit | edit source]You want to allow a user to process a document in one of three ways:
- by using a copy/paste from a text document
- by uploading a file from a local file system
- by referencing a URL
Method
[edit | edit source]We will use a combination of the switch/case with three tabs. The first tab will be for a textarea, the second for a upload control and the third for a URL.
Screen Image
[edit | edit source]The first control on the first tab uses the XForms "textarea" control. This allows users to copy and paste text into a document. The second tab uses an upload control. The upload control will take any file and convert it to a text-encoded XML file. The last tab allows the user to just submit a URL. This URL can then be stored directly into a database or the content can be extracted with other tools.
Depending on different conditions you may want one or more of these controls to be used. The textarea might be the most useful if the content of the document needs to be searched. The other two controls might require a server-side process to extract text for search.
Source Code
[edit | edit source]<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>TriDoc - 3 ways to store text documents</title>
<link rel="stylesheet" type="text/css" href="tri-doc.css"/>
<xf:model>
<xf:instance xmlns="">
<data>
<text/>
<binary xsi:type="xs:base64Binary"/>
<url/>
</data>
</xf:instance>
<xf:submission id="save" action="echo.xq" method="post"/>
</xf:model>
</head>
<body>
<div class="horiz-tabs-menu">
<div id="tab1">
<a href="#tab1">Text
<xf:toggle case="case-1" ev:event="DOMActivate"/>
</a>
</div>
<div id="tab2">
<a href="#tab2">Upload
<xf:toggle case="case-2" ev:event="DOMActivate"/>
</a>
</div>
<div id="tab3">
<a href="#tab3">URL
<xf:toggle case="case-3" ev:event="DOMActivate"/>
</a>
</div>
</div>
<xf:switch>
<xf:case id="case-1" selected="true()">
<xf:label>Text: </xf:label>
<br/>
<xf:textarea ref="text" class="textarea-big"/>
</xf:case>
<xf:case id="case-2">
<xf:upload ref="binary">
<xf:label>Upload: </xf:label>
<xf:filename>file:///C:/tmp/*.xml</xf:filename>
<xf:mediatype>text/xml</xf:mediatype>
</xf:upload>
</xf:case>
<xf:case id="case-3">
<xf:input ref="url" class="url">
<xf:label>URL: </xf:label>
</xf:input>
</xf:case>
</xf:switch>
<div class="test">
<xf:output ref="text">
<xf:label>Text: </xf:label>
</xf:output>
<br/>
<xf:output ref="binary">
<xf:label>Binary: </xf:label>
</xf:output>
<br/>
<xf:output ref="url">
<xf:label>URL: </xf:label>
</xf:output>
</div>
<xf:submit submission="save">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
Sample CSS File
[edit | edit source]@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 */
}
/* the sylying of the divs below each tab */
xf|switch xf|case div {
background: #CCC; /* Light gray */
padding: 0.3em; /* Looks better */
width: 500px;
height: 150px;
-moz-border-radius: 0;
}
.textarea-big textarea {
width: 490px;
height: 120px;
}
.url .xf-value {
width: 450px;
}
Entity Selection
Motivation
[edit | edit source]You want a user interface control that allows a user to select a legal entity in a contract such as a person or an organization. The list of people or organizations are supplied in a list that includes an id and a screen label. You want as-you-type functions to narrow down a list of choices from these lists.
Method
[edit | edit source]We will create a user interface control with two tabs. The first tab will be for people and the second will be for organizations.
Screen Image
[edit | edit source]Source Code
[edit | edit source]<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>Entity Selector</title>
<link rel="stylesheet" type="text/css" href="entity-selector.css"/>
<xf:model>
<xf:instance xmlns="" id="save-data">
<data>
<Person>
<PersonID></PersonID>
<PersonLabel></PersonLabel>
</Person>
<Organization>
<OrganizationID></OrganizationID>
<OrganizationLabel></OrganizationLabel>
</Organization>
</data>
</xf:instance>
<xf:instance xmlns="" id="views">
<data>
<persons></persons>
<organizations></organizations>
</data>
</xf:instance>
<xf:instance xmlns="" id="candidate-people">
<data>
<Person>
<PersonID>1</PersonID>
<PersonLabel>Amy Smith</PersonLabel>
</Person>
<Person>
<PersonID>2</PersonID>
<PersonLabel>Becky Adams</PersonLabel>
</Person>
<Person>
<PersonID>3</PersonID>
<PersonLabel>Mark Daniels</PersonLabel>
</Person>
<Person>
<PersonID>4</PersonID>
<PersonLabel>Dan Jones</PersonLabel>
</Person>
<Person>
<PersonID>5</PersonID>
<PersonLabel>Fred Johnson</PersonLabel>
</Person>
<Person>
<PersonID>6</PersonID>
<PersonLabel>Sue Johnson</PersonLabel>
</Person>
<Person>
<PersonID>7</PersonID>
<PersonLabel>John Doe</PersonLabel>
</Person>
<Person>
<PersonID>8</PersonID>
<PersonLabel>Jane Smith</PersonLabel>
</Person>
<Person>
<PersonID>9</PersonID>
<PersonLabel>Jake Anderson</PersonLabel>
</Person>
<Person>
<PersonID>10</PersonID>
<PersonLabel>Jason Burke</PersonLabel>
</Person>
<Person>
<PersonID>11</PersonID>
<PersonLabel>Jerome Hughes</PersonLabel>
</Person>
<Person>
<PersonID>12</PersonID>
<PersonLabel>Robert Paulson</PersonLabel>
</Person>
<Person>
<PersonID>13</PersonID>
<PersonLabel>Paul Robertson</PersonLabel>
</Person>
</data>
</xf:instance>
<xf:instance xmlns="" id="candidate-organizations">
<data>
<Organization>
<OrganizationID>1</OrganizationID>
<OrganizationLabel>Courts</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>2</OrganizationID>
<OrganizationLabel>County</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>3</OrganizationID>
<OrganizationLabel>Prosecution</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>4</OrganizationID>
<OrganizationLabel>Probation</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>5</OrganizationID>
<OrganizationLabel>Public Defender</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>6</OrganizationID>
<OrganizationLabel>Jails</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>7</OrganizationID>
<OrganizationLabel>Prison</OrganizationLabel>
</Organization>
<Organization>
<OrganizationID>8</OrganizationID>
<OrganizationLabel>State</OrganizationLabel>
</Organization>
</data>
</xf:instance>
<xf:action ev:event="xforms-ready">
<xf:setfocus control="person-input"/>
</xf:action>
<xf:submission id="save"
action="echo.xq" method="post"/>
</xf:model>
</head>
<body>
<h1>Entity Selector</h1>
<p>Select either a person or an organization:</p>
<div class="horiz-tabs-menu">
<div id="tab1">
<a href="#tab1">Person
<xf:toggle case="case-1" ev:event="DOMActivate"/>
</a>
</div>
<div id="tab2">
<a href="#tab2">Organization
<xf:toggle case="case-2" ev:event="DOMActivate"/>
</a>
</div>
</div>
<xf:switch>
<xf:case id="case-1" selected="true()">
<xf:input ref="Person/PersonLabel" incremental="true" class="PersonLabel" id="person-input">
<xf:label>Person: </xf:label>
</xf:input>
<br/>
<div class="autoscroll">
<!-- list all the candidate people and filter out the ones that start with the prefix -->
<xf:repeat
nodeset="instance('candidate-people')/Person[contains(PersonLabel, instance('save-data')/Person/PersonLabel)]"
id="persons-repeat">
<xf:trigger appearance="minimal">
<xf:output ref="PersonLabel"></xf:output> (<xf:output ref="PersonID"></xf:output>)
<!-- now copy the selected item to the save instance -->
<xf:action ev:event="DOMActivate">
<!-- this should work <xf:insert
origin="instance('candidate-people')/Person[index('persons-repeat')]"
nodeset="instance('save-data')/Person"/>
-->
<xf:setvalue
ref="instance('save-data')/Person/PersonLabel"
value="instance('candidate-people')/Person[contains(PersonLabel, instance('save-data')/Person/PersonLabel)][index('persons-repeat')]/PersonLabel" />
<xf:setvalue
ref="instance('save-data')/Person/PersonID"
value="instance('candidate-people')/Person[contains(PersonLabel, instance('save-data')/Person/PersonLabel)][index('persons-repeat')]/PersonID" />
</xf:action>
</xf:trigger>
</xf:repeat>
</div>
</xf:case>
<xf:case id="case-2">
<xf:input ref="Organization/OrganizationLabel" incremental="true">
<xf:label>Organization: </xf:label>
</xf:input>
<div class="autoscroll">
<!-- list all the candidate people and filter out the ones that start with the prefix -->
<xf:repeat
nodeset="instance('candidate-organizations')/Organization[contains(OrganizationLabel, instance('save-data')/Organization/OrganizationLabel)]"
id="organizations-repeat">
<xf:trigger appearance="minimal">
<xf:output ref="OrganizationLabel"></xf:output>
(<xf:output ref="OrganizationID"></xf:output>)
<!-- now copy the selected item to the save instance -->
<xf:action ev:event="DOMActivate">
<xf:setvalue
ref="instance('save-data')/Organization/OrganizationLabel"
value="instance('candidate-organizations')/Organization[contains(OrganizationLabel,
instance('save-data')/Organization/OrganizationLabel)][index('organizations-repeat')]/OrganizationLabel" />
<xf:setvalue
ref="instance('save-data')/Organization/OrganizationID"
value="instance('candidate-organizations')/Organization[contains(OrganizationID,
instance('save-data')/Organization/OrganizationID)][index('organizations-repeat')]/OrganizationID" />
</xf:action>
</xf:trigger>
</xf:repeat>
</div>
</xf:case>
</xf:switch>
<br/><br/>
<div class="test">
<xf:output ref="instance('save-data')/Person/PersonLabel">
<xf:label>Person:</xf:label>
</xf:output>
(<xf:output ref="instance('save-data')/Person/PersonID"/>)
<br/>
<xf:output ref="Organization/OrganizationLabel">
<xf:label>Organization:</xf:label>
</xf:output>
(<xf:output ref="instance('save-data')/Organization/OrganizationID"/>)
</div>
<xf:submit submission="save">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
Repeat into table
Motivation
[edit | edit source]Developers frequently desire to display XML data in tabular structures. Unfortunately the HTML <table>
implementations used in many browsers do not lend themselves to modification.
To circumvent this problem XForms allows you to use repeat inside a table row as an attribute to the HTML <table>
element. So instead of using a <xf:repeat>
element you use a xf:repeat-nodeset
attribute. Note that you must have the xf prefix on the attribute. This is different then the usual process.
Note: This example does not run under the FireFox 0.6 or the 0.7 extension. See Bug 280368 for details.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Repeat Into Table Using xf:repeat-nodeset</title>
<!-- remove this line for non-formfaces implementations -->
<script type="text/javascript" src="formfaces.js"></script>
<xf:model>
<xf:instance xmlns="">
<Data xmlns="">
<Person>
<PersonFullName>John Doe</PersonFullName>
<ContactTelephoneID>(555) 123-4567</ContactTelephoneID>
</Person>
<Person>
<PersonFullName>Jane Smith</PersonFullName>
<ContactTelephoneID>(555) 123-4567</ContactTelephoneID>
</Person>
<Person>
<PersonFullName>Jack Jones</PersonFullName>
<ContactTelephoneID>(555) 123-4567</ContactTelephoneID>
</Person>
<Person>
<PersonFullName>Sue Smith</PersonFullName>
<ContactTelephoneID>(555) 123-4567</ContactTelephoneID>
</Person>
</Data>
</xf:instance>
</xf:model>
</head>
<body>
<table border="1">
<tr>
<th>Name</th>
<th>Telephone Number</th>
</tr>
<tbody xf:repeat-nodeset="Person">
<tr>
<td>
<xf:output ref="PersonFullName" />
</td>
<td>
<xf:output ref="ContactTelephoneID" />
</td>
</tr>
</tbody>
</table>
</body>
</html>
Discussion
[edit | edit source]The line that does the repeat is the table body tag:
<tbody xf:repeat-nodeset="Person">
References
[edit | edit source]W3C Web Page on Repeating Attributes
Repeat filter
Motivation
[edit | edit source]You want to dynamically display a list of items that match an input field as you type. This is character-by-character incremental filtering of possible options. The difference between this and other "suggest" options is that the list of possible options can be stored in an instance.
Method
[edit | edit source]We will put all of the possible choices inside of a xf:repeat statement. When the user types in the input field we will narrow down the choices using an XPath expression in the repeat xf:nodeset attribute. The XPath expression will only match items that begin with specific characters in the xf:input field.
Screen Images
[edit | edit source]Before Filter
[edit | edit source]After Filter
[edit | edit source]Link to working XForms application
[edit | edit source]Sample Program
[edit | edit source]<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>
<xf:model>
<xf:instance id="data" xmlns="">
<data>
<item>
<title>red</title>
</item>
<item>
<title>orange</title>
</item>
<item>
<title>yellow</title>
</item>
<item>
<title>green</title>
</item>
<item>
<title>blue</title>
</item>
<item>
<title>indigo</title>
</item>
<item>
<title>violet</title>
</item>
<item>
<title>black</title>
</item>
<item>
<title>biege</title>
</item>
<item>
<title>brown</title>
</item>
</data>
</xf:instance>
<xf:instance id="search" xmlns="">
<search>
<filter />
</search>
</xf:instance>
<xf:instance id="selected-data" xmlns="">
<data>
<item />
</data>
</xf:instance>
</xf:model>
</head>
<body>
<xf:input ref="instance('search')/filter" incremental="true">
<xf:label>Starts with filter: </xf:label>
</xf:input>
<br />
<xf:repeat
nodeset="instance('data')/item[title[starts-with(., instance('search')/filter)]]"
id="data-list">
<xf:trigger>
<xf:label>Select</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue
ref="instance('selected-data')/item"
value="instance('data')/item[title[starts-with(.,instance('search')/filter)]][index('data-list')]/title" />
</xf:action>
</xf:trigger>
<xf:output ref="title" />
</xf:repeat>
<xf:output ref="instance('selected-data')/item">
<xf:label>Selected: </xf:label>
</xf:output>
</body>
</html>
Discussion
[edit | edit source]The most challenging part of this example is the value attribute of the setvalue element:
<xf:setvalue
ref="instance('selected-data')/item"
value="instance('data')/item[title[starts-with(.,instance('search')/filter)]][index('data-list')]/title" />
We are setting the item of the selected-data instance:
ref=instance('selected-data')/item
We need to set it to the selected value - but the 2nd part - [index('data-list')]
- is the numeric index of the selected item in the filtered list. This is why we 1st have to filter the list and 2nd choose the right index out of the filtered list.
Just like in the restriction of the nodeset attribute of the repeat we are re-running the XPath expression and getting all of the items that start with the text in the filter.
instance('data')item[title[starts-with(.,instance('search')/filter)]]
Note that this is exactly the same expression as in the repeat nodeset attribute.
This list is additionally constrained with the position of the selected item on the data-list:
[index('data-list')]
We are really doing consecutive filters on two sets of data. The first generates the same list as the search. The second uses the item selected to select the correct item.
Attribution
[edit | edit source]This example was originally posted on the mozilla XForms developer group by Chris Sw... on Aug 1st of 2007. A bug was found and fixed by Sivaram Arabandi.
Inline Repeats
Motivation
[edit | edit source]Most computer displays are wider then they are high. So to take advantage of this you sometimes want to grow form data to the right, not down. To do this you must add CSS instructions to use an "inline" display for items within a repeat.
Method
[edit | edit source]CSS has two "display" options:
display:block
adds new elements vertically so the left edge is aligned.display:inline
is horizontal placement where new divs gets added to the right just like new text is added to an input field.
The new elements get added to the current row. By default XForms used a block repeat. But this can be easily changed with a two stylesheet command.
In FireFox the class to modify the attributes of the repeated item is .xf-repeat-item
. Other XForms players may use a different CSS element.
/* Makes the repeated items get added to the right. */
.xf-repeat-item {display:inline;}
/* We MUST put this in to limit the width of the repeated item */
.xf-repeat-item .xf-value {width: 70px;}
Screen Image
[edit | edit source]Executable XForms Application
[edit | edit source]Source Code
[edit | edit source]<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>Inline Repeat</title>
<link rel="stylesheet" type="text/css" href="local.css" />
<xf:model>
<xf:instance xmlns="" id="grid">
<data>
<cell-label>Cell Label 1</cell-label>
<cell-label>A really long label here</cell-label>
<cell-label>Short</cell-label>
<cell-label>Last</cell-label>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Inline Repeat</h1>
<xf:repeat nodeset="cell-label">
<div class="cell">
<xf:output ref="." />
</div>
</xf:repeat>
</body>
</html>
Local CSS File local.css
[edit | edit source]/* CSS file for inline repeat */
@namespace xf url("http://www.w3.org/2002/xforms");
body {
font-family: Helvetica, sans-serif;
}
.cell {
display:inline;
height: 30px;
padding: 8px; margin: 4px;
border: 2px solid blue;
background-color: lightblue;
/* the following only works under FireFox */
-moz-border-radius: 1em;
}
xf|output {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.xf-repeat-item {
display:inline;
}
Discussion
[edit | edit source]In the example above we note that the widths of each cell is determined by the size of the label. Each cell can have a different label. Note that we create a wrapper for each cell using a div. Both the cell wrapper and the .xf-fepeat-item must be set to be display:inline.
Adding Two Dimensional Nesting
[edit | edit source]You can nest repeat groups to create grids of cells. Just make the outer repeat have class attribute to adjust the line height.
Source Code
[edit | edit source]<html
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="http://www.w3.org/1999/xhtml">
<head>
<title>Inline Repeat</title>
<link rel="stylesheet" type="text/css" href="inline-repeat.css" />
<xf:model>
<xf:instance xmlns="" id="grid">
<data>
<row>
<cell-label>Row 1</cell-label>
<cell-label>A really long label here</cell-label>
<cell-label>Short</cell-label>
<cell-label>Last</cell-label>
</row>
<row>
<cell-label>The first cell is the second row has a long label</cell-label>
<cell-label>Row 2 Cell 2</cell-label>
<cell-label>Short</cell-label>
<cell-label>Last Cell</cell-label>
</row>
<row>
<cell-label>Row 3</cell-label>
<cell-label>A really long label here</cell-label>
<cell-label>Short</cell-label>
<cell-label>Last</cell-label>
</row>
<row>
<cell-label>Cell 1</cell-label>
<cell-label>Row 4</cell-label>
<cell-label>Short</cell-label>
<cell-label>The Last Cell of the Last Row</cell-label>
</row>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Inline Repeat</h1>
<xf:repeat nodeset="row" class="row">
<xf:repeat nodeset="cell-label">
<div class="cell">
<xf:output ref="." />
</div>
</xf:repeat>
</xf:repeat>
</body>
</html>
CSS
[edit | edit source]The following CSS will be needed to display a each row on a new line:
.row {
display:block;
line-height: 50px;
}
Scoreboard Example
[edit | edit source]The following example shows how you can put text in before and after the inner repeat.
<html 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="http://www.w3.org/1999/xhtml">
<head>
<title>XForms Scoreboard</title>
<link rel="stylesheet" type="text/css" href="scoreboard.css" />
<xf:model>
<xf:instance xmlns="" id="grid">
<data>
<row>
<team-name>Tigers</team-name>
<score>1</score>
<score>2</score>
<score>3</score>
<score>4</score>
<score>2</score>
<score>3</score>
<total/>
</row>
<row>
<team-name>Dolphins</team-name>
<score>3</score>
<score>2</score>
<score>1</score>
<score>3</score>
<score>2</score>
<score>1</score>
<total/>
</row>
<row>
<team-name>Bears</team-name>
<score>2</score>
<score>2</score>
<score>2</score>
<score>2</score>
<score>2</score>
<score>2</score>
<total/>
</row>
<row>
<team-name>Cubs</team-name>
<score>1</score>
<score>3</score>
<score>2</score>
<score>1</score>
<score>3</score>
<score>2</score>
<total/>
</row>
</data>
</xf:instance>
<xf:bind nodeset="row/total" calculate="sum(../score)"/>
</xf:model>
</head>
<body>
<h1>XForms Scoreboard</h1>
<xf:repeat nodeset="row" class="row">
<xf:output ref="team-name" class="team-name"/>
<xf:repeat nodeset="score">
<xf:output ref="." class="score"/>
</xf:repeat>
<xf:output ref="total" class="total"/>
<br/>
</xf:repeat>
</body>
</html>
Scoreboard CSS
[edit | edit source]/* CSS file for a scoreboard */
@namespace xf url("http://www.w3.org/2002/xforms");
body {
font-family: Helvetica, sans-serif;
}
.row {
line-height: 45px;
}
/* make everything in a row in a line */
.row * {
display:inline;
}
xf|output {
text-align: center;
vertical-align: middle;
font-weight: bold;
height: 30px;
padding: 6px; margin: 4px;
border: 2px solid black;
color: white;
/* the following only works under FireFox */
-moz-border-radius: .2em;
}
.team-name{background-color: blue;}
.total {background-color: green;}
.score {background-color: black;}
Repeats into CSS display tables
[edit | edit source]Get the table to align using CSS.
Here is an example:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="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:xsd="http://www.w3.org/2001/XMLSchema" >
<head>
<title>compact repeat testcase</title>
<style>
@namespace xf url("http://www.w3.org/2002/xforms");
xf|repeat {
display: inline;
}
xf|repeat div {
display: inline;
}
xf|repeat.outer > .xf-repeat-item {
display: table-row;
height: 50px;
padding: 2px; margin 2px;
}
xf|repeat.outer > div > .xf-repeat-item > xf|output > .xf-value {
display: table-cell;
width: 200px;
text-align: center;
padding: 2px; margin 2px;
}
xf|repeat.inner .xf-repeat-item {
display: table-cell;
width: 50px;
background-color: lightblue;
text-align: center;
}
.name {
background-color: pink;
text-align: center;
width: 70px;
height: 35px;
}
.final {
background-color: yellow;
text-align: center;
width: 70px;
}
</style>
<xforms:model>
<xforms:instance id="instdata" xmlns="">
<scores>
<team>
<name>New York Giants</name>
<quarter>3</quarter>
<quarter>0</quarter>
<quarter>0</quarter>
<quarter>14</quarter>
</team>
<team>
<name>New England Patriots</name>
<quarter>0</quarter>
<quarter>7</quarter>
<quarter>0</quarter>
<quarter>7</quarter>
</team>
</scores>
</xforms:instance>
</xforms:model>
</head>
<body>
<h2>Should show a line of data like a NFL box score</h2>
<h3>Uses repeat element</h3>
<br/>
<xforms:repeat class="outer" nodeset="team">
<xforms:output ref="name" class="name"/>
<xforms:repeat class="inner" nodeset="quarter" appearance="compact">
<xforms:output value="."/>
</xforms:repeat>
<xforms:output value="sum(quarter)" class="final"/>
</xforms:repeat>
</body>
</html>
Discussion
[edit | edit source]
Insert
This lab allows you to insert a new row into a tabular structure. We don't use a HTML table here, just a form that updates two items in the model.
Here is the input before you add any new data:
Program Code
[edit | edit source]<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 insert example</title>
<xf:model>
<xf:instance>
<PhoneList xmlns="">
<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>
<NewPerson>
<Name />
<Phone />
</NewPerson>
</PhoneList>
</xf:instance>
</xf:model>
</head>
<body>
<fieldset>
<legend>Company Phone List</legend>
<p>
<b>Name, Phone</b>
<xf:repeat id="list" nodeset="/PhoneList/Person">
<xf:input ref="Name" />
<xf:input ref="Phone" />
</xf:repeat>
</p>
</fieldset>
<fieldset>
<legend>Add New Person</legend>
<p> <!-- here is where we get the new record -->
<xf:input ref="/PhoneList/NewPerson/Name">
<xf:label>Name:</xf:label>
</xf:input>
<br />
<xf:input ref="/PhoneList/NewPerson/Phone">
<xf:label>Phone:</xf:label>
</xf:input>
<xf:trigger>
<xf:label>Insert After Selected Row</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="/PhoneList/Person" at="index('list')" position="after" />
<xf:setvalue ref="/PhoneList/Person[index('list')]/Name" value="/PhoneList/NewPerson/Name" />
<xf:setvalue ref="/PhoneList/Person[index('list')]/Phone" value="/PhoneList/NewPerson/Phone" />
</xf:action>
</xf:trigger>
</p>
</fieldset>
</body>
</html>
Discussion
[edit | edit source]This program has a model of the existing phone list and one additional NewPerson data element at the end of the list. The new person data is linked to the two field form at the end of the table. When you hit the insert button (the trigger) it will copy the data elements from the mini-form and copy them into a new location inside the existing model. The entire list will then be updated. The exact location of where the insert occurs is determined by the index() function. The index is the number of the row you last selected.
There are two items to note. First of all, you can select any row just before you do an insert. The new item will be inserted just after this row.
The second thing to note is that you will still need to be able to delete a record. That is the next lab.
Insert with Origin
Motivation
[edit | edit source]You want to insert new values into an instance of the model and specify where to find the initial values of the insert.
Method
[edit | edit source]You can add an origin attribute to the insert statement to tell XForms where to get the initial data for the insert. This is the preferred method over doing many setvalues. The syntax of the insert is the following:
<xf:insert ev:event="DOMActivate"
nodeset="instance('persons')/Person"
at="last()" position="after"
origin="instance('init')/Person"/>
Screen Image
[edit | edit source]A sample screen image. Many people do not have the ability to run the examples so this is critical.
Use this format:
Make SURE you label all images with a license. Please use creative commons "share alike 3.0 with attribution" if you can.
XForms Application
[edit | edit source]Make sure that the mime-type is set in the svn system to be text/xml.
Sample XForms Template
[edit | edit source]<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>Insert with Origin</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="persons">
<data>
<Person>
<PersonGivenName>John</PersonGivenName>
<PersonFamilyName>Doe</PersonFamilyName>
<PersonGenderCode>unknown</PersonGenderCode>
<XFormsAwareIndicator>false</XFormsAwareIndicator>
</Person>
<Person>
<PersonGivenName>Sue</PersonGivenName>
<PersonFamilyName>Smith</PersonFamilyName>
<PersonGenderCode>unknown</PersonGenderCode>
<XFormsAwareIndicator>false</XFormsAwareIndicator>
</Person>
</data>
</xf:instance>
<xf:bind nodeset="XFormsAwareIndicator" type="xs:boolean"/>
<!-- initial values for new Person records -->
<xf:instance xmlns="" id="init">
<data>
<Person>
<PersonGivenName></PersonGivenName>
<PersonFamilyName></PersonFamilyName>
<PersonGenderCode>unknown</PersonGenderCode>
<XFormsAwareIndicator>false</XFormsAwareIndicator>
</Person>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<h3>Insert with Origin</h3>
<xf:repeat nodeset="Person" id="person-repeat">
<xf:input ref="PersonGivenName">
<xf:label>First Name: </xf:label>
</xf:input>
<xf:input ref="PersonFamilyName">
<xf:label>Family Name: </xf:label>
</xf:input>
<xf:select1 ref="PersonGenderCode">
<xf:label>Gender: </xf:label>
<xf:item>
<xf:label>Male</xf:label>
<xf:value>male</xf:value>
</xf:item>
<xf:item>
<xf:label>Female</xf:label>
<xf:value>female</xf:value>
</xf:item>
<xf:item>
<xf:label>Unknown</xf:label>
<xf:value>unknown</xf:value>
</xf:item>
</xf:select1>
<xf:input ref="XFormsAwareIndicator">
<xf:label>Indicator: </xf:label>
</xf:input>
</xf:repeat>
<xf:trigger>
<xf:label>Add</xf:label>
<xf:insert ev:event="DOMActivate" nodeset="instance('persons')/Person" at="last()" position="after"
origin="instance('init')/Person"/>
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]
Delete
Deleting an item from a list
[edit | edit source]Here is a sample program to delete an item from a list of items. The selected item can be deleted by selecting the row you wish to delete and selecting the "Delete" button. This trigger has the following format:
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete ref="//Person[index('person-repeat')]"/>
</xf:action>
</xf:trigger>
There are two attributes to the delete element. The nodeset indicates what set of nodes you select the item from and the at indicates the node number. We used the index function to get the number of the selected node.
Screen Image
[edit | edit source]The form has a list of people. You can add and delete to the selected row.
Sample Program
[edit | edit source]XForms code
[edit | edit source]<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 Delete Example</title>
<link rel="stylesheet" type="text/css" href="delete2.css" />
<xf:model>
<xf:instance id="people">
<PhoneList xmlns="">
<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>
<NewPerson>
<Name />
<Phone />
</NewPerson>
<SelectedRow />
</PhoneList>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group nodeset="/PhoneList">
<fieldset>
<legend>Company Phone List</legend>
<!-- this lists all the people -->
<xf:repeat id="person-repeat" ref="Person">
<xf:input ref="Name" />
<xf:input ref="Phone" />
</xf:repeat>
</fieldset>
<xf:trigger>
<legend>Add Row</legend>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="Person" at="index('person-repeat')" position="after" />
<xf:setvalue ref="Person[index('person-repeat')]/Name"
value="/PhoneList/NewPerson/Name" />
<xf:setvalue ref="Person[index('person-repeat')]/Phone"
value="/PhoneList/NewPerson/Phone" />
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Delete Selected Row</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete ref="instance('people')//Person[index('person-repeat')]"/>
</xf:action>
</xf:trigger>
<br />
<xf:output value="index('person-repeat')">
<xf:label>Selected Row= </xf:label>
</xf:output>
</xf:group>
</body>
</html>
CSS stylesheet
[edit | edit source]* {
font-family: Arial, Helvetica, sans-serif;
}
label, legend {
font-weight: bold;
}
contextcontainer {
display: table-row;
}
input {
display: table-cell;
color: white;
background-color: gray;
}
/* Display for the selected line */
.xf-repeat-index input {
color: black;
background-color: white;
}
Discussion
[edit | edit source]Note that you can still select a row and insert a new record after it. But you can also select any row and now delete it.
To keep this example simple the header of table columns have been forgotten (see Repeat into table how the table should behave).
The code for the selected line should be:
*::repeat-index input {
color: black;
background-color: white;
}
but this doesn't work with Firefox 2.0.0.14 + Mozilla XForms 0.8.5
To Do
[edit | edit source]Figure out how to modify the style sheet so that the selected row is hilighted. The XForms documentation implies that ::value is the active areas, ::repeat-item is a single item from a list of repeating sequence and that ::repeat-index is the current item of a repeating sequence
These do not appear to work with the style sheet under FireFox 0.6.
Potential problem: when you have deleted all the nodes, the insert trigger does not work anymore. This is because the nodeset selection on the insert element is empty in that situation. If the nodeset selector is empty, the insert trigger has no meaning (see the first rule in 'rules for insert processing')
Disable Trigger
Motivation
[edit | edit source]There is a specific delete trigger on each row of a table or each item of a list. You want to disable the delete (button) trigger if there is only a single item remaining in the list.
Sample Code
[edit | edit source]<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 Trigger</title>
<xf:model>
<xf:instance id="my-instance" xmlns="">
<data>
<item>Item 1</item>
<item>Item 2</item>
<item>Item 3</item>
</data>
</xf:instance>
<xf:instance id="views" xmlns="">
<data>
<item-delete-trigger />
</data>
</xf:instance>
<!-- display the delete button only if there is a second item -->
<xf:bind id="item-delete-trigger"
nodeset="instance('views')/item-delete-trigger"
relevant="instance('my-instance')/item[2]"/>
</xf:model>
</head>
<body>
<xf:repeat nodeset="instance('my-instance')/item" id="item-repeat">
<xf:input ref=".">
<xf:label>Item: </xf:label>
</xf:input>
<xf:trigger bind="item-delete-trigger">
<xf:label>Delete</xf:label>
<xf:delete nodeset="instance('my-instance')/item[index('item-repeat')]"
ev:event="DOMActivate" />
</xf:trigger>
</xf:repeat>
<xf:trigger>
<xf:label>Append</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('my-instance')/item" at="last()" position="after" />
<!-- set the value to the item count -->
<xf:setvalue ref="instance('my-instance')/item[last()]"
value="concat('Item ', count(instance('my-instance')/item))" />
</xf:action>
</xf:trigger>
<xf:trigger bind="item-delete-trigger">
<xf:label>Delete Selected Row</xf:label>
<xf:delete nodeset="instance('my-instance')/item[index('item-repeat')]"
ev:event="DOMActivate" />
</xf:trigger>
</body>
</html>
Discussion
[edit | edit source]This example uses two named instances. The my-instance is the data that would be submitted with the form. The views instance is just used to bind a view of the form with some logic. This is done in a bind statement.
<xf:bind id="item-delete-trigger"
nodeset="instance('views')/item-delete-trigger"
relevant="count(instance('my-instance')/item) > 1" />
This says that the item delete trigger should only be present if there is more than one item.
Although the above is logically correct, there is really no need to count all the items and do a comparison. You can enable the trigger if the second item is present.
<xf:bind id="item-delete-trigger"
nodeset="instance('views')/item-delete-trigger"
relevant="instance('save-data')/item[2]" />
This syntax is preferred since it is faster and the greater than sign does not have to be escaped.
Delete Confirm
Motivation
[edit | edit source]Since users frequently spend a lot of time entering data, you want to make sure that if you allow them to delete that they didn't accidentally click on the delete or that they have selected the correct element when they do actually delete a part of the form.
This example uses the XForms switch
and case
statements to conditionally display a delete confirmation dialog. This many not be the most elegant way of doing this. Ideally a future version of XForms will add a confirm="yes" option to the delete trigger. But till then you can use the following example.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<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 Delete Example</title>
<style type="text/css">
* {
font-family: Arial, Helvetica, sans-serif;
}
label {
font-weight: bold;
}
.header {
color: white;
background-color: gray;
font-weight: bold;
padding: 2px;
}
.header {
width: 370px;
}
.leftColumn, .rightColumn {
display: inline;
}
.leftColumn {
margin-left: 10px;
}
.rightColumn {
position: absolute;
left: 0;
margin-left: 150px;
}
</style>
<xf:model>
<xf:instance id="contacts" xmlns="">
<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>
<NewPerson>
<Name />
<Phone />
</NewPerson>
<SelectedRow />
</PhoneList>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group nodeset="/PhoneList">
<xf:label class="group-label">Company Phone List</xf:label>
<div class="header">
<div class="leftColumn">Name</div>
<div class="rightColumn">Phone</div>
</div>
<xf:repeat id="contact-repeat" nodeset="Person">
<xf:input ref="Name" class="leftColumn" />
<xf:input ref="Phone" class="rightColumn" />
</xf:repeat>
</xf:group>
<xf:group>
<xf:label class="group-label">Add/Delete Person</xf:label>
<br />
<xf:input ref="NewPerson/Name">
<xf:label>Name:</xf:label>
</xf:input>
<br />
<xf:input ref="NewPerson/Phone">
<xf:label>Phone:</xf:label>
</xf:input>
<br />
<xf:trigger>
<xf:label>Insert After Selected Row</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="Person" at="index('contact-repeat')" position="after" />
<xf:setvalue ref="Person[index('contact-repeat')]/Name" value="/PhoneList/NewPerson/Name" />
<xf:setvalue ref="Person[index('contact-repeat')]/Phone" value="/PhoneList/NewPerson/Phone" />
<xf:setvalue ref="SelectedRow" value="index('contact-repeat')" />
</xf:action>
</xf:trigger>
<br />
<xf:switch>
<xf:case id="delete">
<!-- don't display the delete trigger unless we have at lease one person -->
<xf:trigger ref="instance('contacts')[count(//Person) > 1]">
<xf:label>Delete person</xf:label>
<xf:action ev:event="DOMActivate">
<xf:toggle case="confirm" />
</xf:action>
</xf:trigger>
</xf:case>
<xf:case id="confirm">
<h2>Are you sure you want to delete the following:</h2>
<div id="content-for-deletion">
<p>Description: <xf:output ref="Person[index('contact-repeat')]/Name" />
</p>
<p>Value: <xf:output ref="Person[index('contact-repeat')]/Phone" />
</p>
</div>
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="Person[index('contact-repeat')]" at="index('contact-repeat')" ev:event="DOMActivate" />
<xf:toggle case="delete" />
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Cancel</xf:label>
<xf:toggle case="delete" ev:event="DOMActivate" />
</xf:trigger>
</xf:case>
</xf:switch>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]We use the XForms switch and case statements to reveal the confirmation dialog. The dialog also indicates what record is going to be deleted.
This example does not use CSS to have the dialog appear to display in a separate window above the form. This can be done by wrapping the dialog in divs and styling the divs with CSS.
In the future our hope is that a the delete tag will have a confirmation option such as
<xf:delete confirmation="true" confirmation-message="XPath">
Where the message displayed would be a confirmation message.
References
[edit | edit source]This example was suggested by Alex Bleasdale.
Delete Confirm with CSS
Motivation
[edit | edit source]One of the nice things about using the switch statement is that you can quickly display HTML that has absolute positioning over the current form. This is done by adding some div elements that reference a style sheet. Although this example is for a delete confirmation, it can be use in any place you need to have a model dialog with messages and a cancel button.
Screen Image
[edit | edit source]Link to Example Program
[edit | edit source]Sample Program
[edit | edit source]<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 Delete Example</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Arial, Helvetica, sans-serif; font-size:75%; margin:0; padding:0; width:370px;}
label {font-weight: bold;}
.header {
color: white;
background-color: gray;
font-weight: bold;
float:left;
width:370px;
}
.header .leftColumn, .header .rightColumn {
display:block; width:11em; float:left; margin:5px 10px;
}
.leftColumn, .rightColumn {
display: inline; margin-left: 10px;
}
/* This marks the "selected" point within a set of repeated elements */
xf|repeat {background:#eee; float:left; width:370px;}
xf|repeat .xf-value {margin:3px 0;}
xf|repeat .xf-repeat-item {border:1px solid #eee;}
xf|repeat .xf-repeat-index {background:#999; border:1px dotted black; }
xf|input .xf-value {width:10em;}
/* model delete confirmation box */
#background {position:fixed; top:0; left:0; background:#888; width:100%; height:110%;}
#delete-confirm-box {width:500px; height:250px; border:3px dotted #1c5180; background:#ddd; margin:auto; margin-top:200px;}
#delete-option-triggers {text-align:center; width:100%; margin-top:-70px;}
xf|trigger {margin-right:20px;}
#content-for-deletion {float:left; width:340px; position:relative; top:0; left:0; padding:10px;}
#content-for-deletion p {padding:0; margin-bottom:10px; font-weight:bold; font-size:1.2em;}
#delete-confirm-box h2 {font-size:1.5em; margin:0; padding:5px; color:#fff; font-family:Century Gothic; text-align:center; background:#3e7c8f;}
</style>
<xf:model>
<xf:instance id="contacts" xmlns="">
<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>
<NewPerson>
<Name />
<Phone />
</NewPerson>
<SelectedRow />
</PhoneList>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group nodeset="/PhoneList">
<xf:label class="group-label">Company Phone List</xf:label>
<div class="header">
<div class="leftColumn">Name</div>
<div class="rightColumn">Phone</div>
</div>
<xf:repeat id="contact-repeat" nodeset="Person">
<xf:input ref="Name" class="leftColumn" />
<xf:input ref="Phone" class="rightColumn" />
</xf:repeat>
</xf:group>
<xf:group>
<xf:label class="group-label">Add/Delete Person</xf:label>
<br />
<xf:input ref="NewPerson/Name">
<xf:label>Name:</xf:label>
</xf:input>
<br />
<xf:input ref="NewPerson/Phone">
<xf:label>Phone:</xf:label>
</xf:input>
<br />
<xf:trigger>
<xf:label>Insert After Selected Row</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="Person" at="index('contact-repeat')" position="after" />
<xf:setvalue ref="Person[index('contact-repeat')]/Name" value="/PhoneList/NewPerson/Name" />
<xf:setvalue ref="Person[index('contact-repeat')]/Phone" value="/PhoneList/NewPerson/Phone" />
<xf:setvalue ref="SelectedRow" value="index('contact-repeat')" />
</xf:action>
</xf:trigger>
<br />
<xf:switch>
<xf:case id="delete">
<!-- don't display the delete button unless we have at two or more records -->
<xf:trigger ref="instance('contacts')[count(//Person) > 1]">
<xf:label>Delete person</xf:label>
<xf:action ev:event="DOMActivate">
<xf:toggle case="confirm" />
</xf:action>
</xf:trigger>
</xf:case>
<xf:case id="confirm">
<div id="background">
<div id="delete-confirm-box">
<h2>Are you sure you want to delete the following:</h2>
<div id="content-for-deletion">
<p>Description: <xf:output ref="Person[index('contact-repeat')]/Name" />
</p>
<p>Value: <xf:output ref="Person[index('contact-repeat')]/Phone" />
</p>
</div>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<radialGradient id="alert-gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0" style="stop-color:#f92500; stop-opacity:0.7" />
<stop offset="1" style="stop-color:#f92500; stop-opacity:1" />
</radialGradient>
<!-- base triangle -->
<polygon points="10,110 70,10 130,110" style="fill:url(#alert-gradient); stroke:#fff; stroke-width:3" />
<!-- exclamation mark -->
<rect x="65" y="40" width="10" height="40" style="fill:#000; stroke:#fff; stroke-width:2" />
<rect x="65" y="90" width="10" height="10" style="fill:#000; stroke:#fff; stroke-width:2" />
</svg>
<div id="delete-option-triggers">
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="Person[index('contact-repeat')]" at="index('contact-repeat')" ev:event="DOMActivate" />
<xf:toggle case="delete" />
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Cancel</xf:label>
<xf:toggle case="delete" ev:event="DOMActivate" />
</xf:trigger>
</div>
</div>
</div>
</xf:case>
</xf:switch>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]This example appears to show a new window on top of the existing form. This is called a modal window because you can not make any further changes to the form without a confirmation or cancel action.
Acknowledgment
[edit | edit source]This example program was contributed by a CSS guru who wishes to remain anonymous till he has more time to make the example better.
Trailing Insert and Delete
Motivation
[edit | edit source]In some instances you only want to add to the end of a list or delete from the end of a list. This program demonstrates how you can use the last()
function to do this.
Screen Image
[edit | edit source]When you insert a new row, it will always be inserted at the end of the list. When you delete a row, it will also be removed from the end of the list.
Link to XForms Application
[edit | edit source]Sample Program
[edit | edit source]<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>Repeat Demo</title> <xf:model> <xf:instance xmlns=""> <data xmlns=""> <val>1</val> <val>2</val> <val>3</val> </data> </xf:instance> </xf:model> </head> <body> <xf:repeat nodeset="val"> <div> <xf:output ref="."> <xf:label>Value: </xf:label> </xf:output> </div> </xf:repeat> <xf:trigger> <xf:label>Insert new row</xf:label> <xf:action ev:event="DOMActivate"> <xf:insert nodeset="val" position="after" at="last()" /> <xf:setvalue ref="val[last()]" value="count(/data/val)" /> </xf:action> </xf:trigger> <xf:trigger> <xf:label>Delete last row</xf:label> <xf:delete nodeset="val" at="last()" ev:event="DOMActivate" /> </xf:trigger> </body> </html>
Discussion
[edit | edit source]Notice that the xf:insert
uses the xf:action
element to trigger on the DOM activate and the xf:delete
uses the ev:event
attribute to trigger the delete. This is because we need to include the xf:setvalue
in the insert.
So, as a general rule, if you just need to use a single element in a trigger, you can use the ev:event
attribute. But if you need to include several elements that all must be triggered you should wrap them in an an xf:action
element.
Potential problem: when you have deleted all the nodes, the insert trigger does not work anymore. This is because the nodeset selection on the insert element is empty in that situation. If the nodeset selector is empty, the insert trigger has no meaning (see the first rule in 'rules for insert processing')
References
[edit | edit source]
Insert and Delete into Table
Motivation
[edit | edit source]You want to insert and delete records into a table. In this example records are appended to the end of a table but any selected row can be removed. This example does "in-place" table editing. There is no separate form to enable viewing a new record other than in the actual table.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
* { font-family: Ariel, Helvetica, sans-serif }
.table-header {
display: table-row;
}
.column-header {
display: table-cell;
text-align: center;
width: 185px;
color: white;
background-color: gray;
font-weight: bold;
}
</style>
<title>Demonstration of inserting and deleting records from a table</title>
<xf:model id="phone-list">
<xf:instance id="my-phone-list" src="phone-list.xml" xmlns="" />
<xf:submission id="update-from-local-file" method="get" action="phone-list.xml"
replace="instance" instance="my-phone-list"/>
<xf:submission id="view-xml-instance" method="get" action="phone-list.xml" />
<xf:submission id="save-to-local-file" method="put" action="phone-list.xml" />
</xf:model>
</head>
<body>
<!-- table header -->
<div class="table-header">
<div class="column-header">Name</div>
<div class="column-header">Phone</div>
</div>
<!-- For each Person in the PersonList display the name and phone-->
<xf:repeat ref="/PhoneList/Person" id="repeatPerson">
<xf:input id="name-input" ref="Name"/>
<xf:input ref="Phone"/>
<br/>
</xf:repeat>
<xf:trigger>
<xf:label>Add Person</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert ref="/PhoneList/Person[last()]" position="after" at="last()"/>
<xf:setvalue ref="/PhoneList/Person[last()]/Name" value="''"/>
<xf:setvalue ref="/PhoneList/Person[last()]/Phone" value="''"/>
<!-- put the cursor in the name field -->
<xf:setfocus control="name-input"/>
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Delete Person</xf:label>
<xf:delete nodeset="/PhoneList/Person[index('repeatPerson')]"
at="index('repeatPerson')" ev:event="DOMActivate" />
</xf:trigger>
<br/>
<xf:submit submission="update-from-local-file">
<xf:label>Reload</xf:label>
</xf:submit>
<xf:submit submission="save-to-local-file">
<xf:label>Save</xf:label>
</xf:submit>
<xf:submit submission="view-xml-instance">
<xf:label>View XML Instance</xf:label>
</xf:submit>
</body>
</html>
Discussion
[edit | edit source]This example uses the last() and index() XPath functions to find out what row of the table should be operated on.
You can also create a version that has a delete and add button in each row. In this design the index() function is used to delete the current row selected and insert after the currently selected row.
In some applications the order of rows is important. You can also add buttons to each row to move the selected row up or down.
Note that after you add the row, you should move the insert cursor to the first field. This is done by using the setfocus element.
References
[edit | edit source]
Code Table Editor
Code Table Editor
<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/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">
<head>
<title>Reference Code Editor</title>
<meta name="description" content="Bookmarks management sample."/>
<meta name="keywords" content="AJAX, Javascript, Web, XForms, XSLTForms, Exemples, Samples"/>
<xf:model>
<xf:instance>
<code-table xmlns="">
<code-name>Code Table Name</code-name>
<desc>A reference list for HIPAA Gender Codes</desc>
<items>
<item>
<value>F</value>
<label>Female</label>
<desc>Female gender</desc>
</item>
<item>
<value>M</value>
<label>Male</label>
<desc>Male gender</desc>
</item>
<item>
<value>U</value>
<label>Unknown</label>
<desc>Unknown gender</desc>
</item>
</items>
</code-table>
</xf:instance>
<xf:submission id="save" method="post" show="new" replace="all" action="/unit-tests/view-post.xqy">
<xf:message level="modeless" ev:event="xforms-submit-error">Submit error.</xf:message>
</xf:submission>
</xf:model>
</head>
<body>
<h3>Bookmarks</h3>
<xf:input ref="code-name">
<xf:label>Code Table Name: </xf:label>
</xf:input>
<br/>
<xf:textarea ref="desc" class="big-textarea" style="width:500px; height:100px;">
<xf:label>Desc: </xf:label>
</xf:textarea>
<br/>
<!-- TODO - put this in a Bootstrap table -->
<xf:repeat id="repeatItems" nodeset="items/item" appearance="compact">
<xf:input ref="value">
<xf:label>Value</xf:label>
</xf:input>
<xf:input ref="label">
<xf:label>Label</xf:label>
</xf:input>
<xf:input ref="desc">
<xf:label>Desc</xf:label>
</xf:input>
<xf:trigger>
<xf:label>X</xf:label>
<xf:delete nodeset="." at="1" ev:event="DOMActivate" if="count(//item) > 1"/>
</xf:trigger>
</xf:repeat>
<xf:trigger>
<xf:label>New Item</xf:label>
<xf:insert nodeset="items/item" at="index('repeatItems')"
position="after" ev:event="DOMActivate" />
<!-- todo, use a copy from template or use setvalue to make it zero -->
</xf:trigger>
<xf:trigger>
<xf:label>Delete Current Selected Item</xf:label>
<xf:delete nodeset="." at="1" ev:event="DOMActivate"
if="count(//item) > 1" />
</xf:trigger>
<br/>
<xf:submit submission="save">
<xf:label>Save</xf:label>
</xf:submit>
</body>
</html>
Highlight Selected Row
Motivation
[edit | edit source]It is very often useful to highlight the selected row. This is done with a xform-repeat-index pseudo element in the style sheet.
CSS
[edit | edit source]By adding the following to your CSS the selected row will be highlighted in blue:
.xforms-repeat-index {
background-color: blue;
}
Screen Image
[edit | edit source]This example highlights the background of the selected row.
This example was run using the FormFaces system.
Program Code
[edit | edit source]<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 Delete Example</title>
<!-- I used the formfaces system to test this -->
<script type="text/javascript" src="formfaces.js"></script>
<style type="text/css">
* {
font-family: Ariel, Helvetica, sans-serif;
}
label, legend {
font-weight: bold;
}
.header {
color: white;
background-color: gray;
font-weight: bold;
padding: 2px;
}
.header {
width: 370px;
}
.leftColumn, .rightColumn {
display: inline;
}
.leftColumn {
margin-left: 10px;
}
.rightColumn {
position: absolute;
left: 0;
margin-left: 150px;
}
fieldset {
width: 380px;
}
.xforms-repeat-index {
background-color: blue;
}
</style>
<xf:model>
<xf:instance>
<PhoneList xmlns="">
<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>
<NewPerson>
<Name />
<Phone />
</NewPerson>
<SelectedRow />
</PhoneList>
</xf:instance>
</xf:model>
</head>
<body>
<xf:group nodeset="/PhoneList">
<fieldset>
<legend>Company Phone List</legend>
<div class="header">
<div class="leftColumn">Name</div>
<div class="rightColumn">Phone</div>
</div>
<xf:repeat id="list" nodeset="Person">
<xf:input ref="Name" class="leftColumn"><xf:label></xf:label></xf:input>
<xf:input ref="Phone" class="rightColumn"><xf:label></xf:label></xf:input>
</xf:repeat>
</fieldset>
<fieldset>
<legend>Add New Person</legend>
<xf:input ref="NewPerson/Name">
<xf:label>Name:</xf:label>
</xf:input>
<br />
<xf:input ref="NewPerson/Phone">
<xf:label>Phone:</xf:label>
</xf:input>
<xf:trigger>
<xf:label>Insert After Selected Row</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="Person" at="index('list')" position="after" />
<xf:setvalue ref="Person[index('list')]/Name" value="/PhoneList/NewPerson/Name" />
<xf:setvalue ref="Person[index('list')]/Phone" value="/PhoneList/NewPerson/Phone" />
<xf:setvalue ref="SelectedRow" value="index('list')" />
</xf:action>
</xf:trigger>
</fieldset>
<xf:trigger>
<xf:label>Delete Selected Row</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="Person" at="index('list')" />
</xf:action>
</xf:trigger>
<xf:output ref="SelectedRow">
<xf:label>Selected Row= </xf:label>
</xf:output>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]Note that this only works when you select a row an click your cursor on the input field. The result is that the value of the index for the selected list will change. This can be used by the functions that add or delete a selected row.
Known bugs
[edit | edit source]This appears to not be functional under the FireFox extension as of 0.6.
Table Column Total
Motivation
[edit | edit source]Frequently a form must display the total of a column. This can be accomplished using the bind function in the model.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/xforms"
>
<head>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
* { font-family: Ariel, Helvetica, sans-serif }
.table-header, .table-footer {
display: table-row;
}
.column-header, .column-footer {
display: table-cell;
text-align: center;
color: white;
background-color: gray;
font-weight: bold;
}
/* make the "Total:" in the table footer right align */
.table-footer .item-description,
.table-footer .item-amount {
text-align: right;
}
.item-description {
width: 300px;
}
.item-amount {
width: 112px;
}
.item-description .xf-value {
width: 300px;
text-align: left
}
.item-amount .xf-value {
width: 100px;
text-align: right
}
</style>
<title>Demonstration of table with column total</title>
<xf:model id="my-model">
<xf:instance id="my-data" src="my-data.xml" xmlns=""/>
<xf:bind nodeset="/Data/Total" calculate="sum(../Item/Amount)"/>
<xf:submission id="update-from-local-file" method="get" action="my-data.xml"
replace="instance" instance="my-crv"/>
<xf:submission id="view-xml-instance" method="get" action="my-data.xml"/>
<xf:submission id="save-to-local-file" method="put" action="my-data.xml"/>
</xf:model>
</head>
<body>
<div class="table-header">
<div class="column-header item-description">Description</div>
<div class="column-header item-amount">Value</div>
</div>
<xf:group ref="/Data">
<!-- For each Person in the PersonList display the name and phone-->
<xf:repeat nodeset="Item" id="repeatItem">
<xf:input id="description-input" ref="Description" class="item-description"/>
<xf:input ref="Amount" class="item-amount"/>
<br />
</xf:repeat>
<div class="table-footer">
<div class="column-footer item-description">Total:</div>
<div class="column-footer item-amount">
<xf:output ref="/Data/Total" />
</div>
</div>
<xf:trigger id="insertbutton">
<xf:label>Add Item</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="Item[last()]" position="after" at="last()"/>
<xf:setvalue ref="Item[last()]/Description" value="''"/>
<xf:setvalue ref="Item[last()]/Amount" value="0"/>
<!-- put the cursor in the name field -->
<xf:setfocus control="description-input"/>
</xf:action>
</xf:trigger>
<xf:trigger id="delete">
<xf:label>Delete Item</xf:label>
<xf:delete nodeset="Item[index('repeatItem')]"
at="index('repeatItem')" ev:event="DOMActivate"/>
</xf:trigger>
<br />
<xf:submit submission="update-from-local-file">
<xf:label>Reload</xf:label>
</xf:submit>
<xf:submit submission="save-to-local-file">
<xf:label>Save</xf:label>
</xf:submit>
<xf:submit submission="view-xml-instance">
<xf:label>View XML Instance</xf:label>
</xf:submit>
</xf:group>
</body>
</html>
Sample my-data.xml instance file
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?> <Data> <Item> <Description>Furniture</Description> <Amount>1000</Amount> </Item> <Item> <Description>Dock</Description> <Amount>2000</Amount> </Item> <Item> <Description>Boat</Description> <Amount>3000</Amount> </Item> <Item> <Description>Lawn equipment</Description> <Amount>4000</Amount> </Item> <Item> <Description>Hot tub</Description> <Amount>5000</Amount> </Item> <Total>15000</Total> </Data>
Discussion
[edit | edit source]This example uses div blocks for the table header and footer. The total will be updated each time the user tabs out of a field. New items are always added to the end but you can delete an existing item just by selecting it and pressing the "Delete item" button.
Multiple Uploads
Motivation
[edit | edit source]You would like the user to be able to attach multiple files to a form.
Method
[edit | edit source]We will use the <xf:repeat> around the upload control:
Sample Source
[edit | edit source]<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:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>XForms Upload Multiple Simple</title>
<xf:model>
<xf:instance xmlns="" id="save-data">
<formdata>
<Files1>
<MyFile filename="" mediatype="" size=""></MyFile>
</Files1>
</formdata>
</xf:instance>
<xf:instance id="file-upload-template" xmlns="">
<MyFile filename="" mediatype="" size=""></MyFile>
</xf:instance>
</xf:model>
</head>
<body>
<p>Demonstration of how to use the repeat element to get multiple uploads.</p>
<fieldset>
<legend>Add multiple attachments</legend>
<xf:repeat ref="instance('save-data')/Files1/MyFile" id="repeat-1">
<xf:upload ref=".">
<xf:filename ref="@filename"></xf:filename>
<xf:mediatype ref="@mediatype"></xf:mediatype>
<xxforms:size ref="@size"></xxforms:size>
<!-- Note the event after upload could add a new row -->
</xf:upload>
<xf:trigger ref="instance('save-data')/Files1/MyFile[2]">
<xf:label>Delete</xf:label>
<xf:delete ev:event="DOMActivate"
ref="instance('save-data')/Files1/MyFile[index('repeat-1')]"></xf:delete>
</xf:trigger>
<br />
</xf:repeat>
<xf:trigger>
<xf:label>Add Attachment</xf:label>
<xf:insert ev:event="DOMActivate" ref="instance('save-data')/Files1/MyFile"
origin="instance('file-upload-template')"> </xf:insert>
</xf:trigger>
</fieldset>
<fr:xforms-inspector></fr:xforms-inspector>
</body>
</html>
Sample User Interface
[edit | edit source]User interface notes
[edit | edit source]- The delete trigger will only be visible after the second upload is shown.
- This interface shows the file name and size in bytes. The mime-type could also be shown
- You can add any number of files
- You can delete any row by selecting the "Delete" button
- You can re-add a file using the red X
The files will be uploaded to the server in an async process.
Tested on Orbeon 4.3
Summary Details
Motivation
[edit | edit source]You have a long list of items, each of which has around a half screen of item details to edit. You want to quickly scroll through a table of items and change the details for the selected item.
Method
[edit | edit source]We will split our screen into two parts. The top part provides a tabular list list of items with each item displayed on a single line. As you select a single item, the details for that item will be shown on the lower part of the screen.
Screen Image
[edit | edit source]Note that when the mouse is in the second row the inspector is focused on the second item.
Sample Code
[edit | edit source]The way we get the bottom panel to change context to the selected row is to use a <xf:group> element that will always focus on the selected row.
<xf:group ref="instance('save-data')//item[index('item-repeat')]">
In this example the index('item-repeat') function will always be set to the selected row. So when you are on the second row the index('item-repeat') will be set to 2 and the XPath expression will be instance('save-data')//item[2]
Here is the full source code:
<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>Summary-Inspector Pattern</title>
<xf:model>
<!-- The top part of the form shows a summary row for each record. The bottom has details for each row. -->
<xf:instance id="save-data">
<items xmlns="">
<item>
<name>Table Name 1</name>
<description>Table Description 1</description>
</item>
<item>
<name>Table Table Name 2</name>
<description>Table Description 2</description>
</item>
<item>
<name>Table Name 3</name>
<description>Table Description 3</description>
</item>
<item>
<name>Table Name 4</name>
<description>Table Description 4</description>
</item>
</items>
</xf:instance>
<xf:instance id="template">
<item xmlns="">
<name></name>
<description></description>
</item>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Summary-Inspector Pattern</h1>
<xf:repeat id="item-repeat" nodeset="instance('save-data')//item">
<xf:input ref="name"></xf:input>
<xf:input ref="description"></xf:input>
<xf:trigger>
<xf:label>X</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="."/>
</xf:trigger>
</xf:repeat>
<xf:trigger>
<xf:label>Add</xf:label>
<xf:insert ev:event="DOMActivate" nodeset="instance('save-data')/items" origin="instance('template')" at="last()" position="after"/>
</xf:trigger>
<xf:group ref="instance('save-data')//item[index('item-repeat')]">
<fieldset>
<legend>Item inspector</legend>
<xf:input ref="name">
<xf:label>Name: </xf:label>
</xf:input>
<xf:input ref="description">
<xf:label>Description: </xf:label>
</xf:input>
</fieldset>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]Note that this pattern may be extended to use multi-line tables and a scrolling div in the top part of the form.
Load from XML Schema
Motivation
[edit | edit source]Many times the data types of your data are defined in an external XML Schema file. To use this information, rather than having to explicitly bind the instance to a data type, you can just load the XML Schema file to initialize instance data in the model. The data types will be inferred from the XML Schema file.
To do this you must add a schema
attribute to the model where the value of the argument is the XML Schema source file. Note that the argument is schema
NOT src
. src
is used to read in the instance data.
<xf:model id="test" schema="data-types.xsd">
<xf:instance src="instance-data.xml"/>
</xf:model>
Screen Image
[edit | edit source]Here is a screen image of a sample program. Note that input form for the date and boolean data types are automatically inferred from the XML Schema and different controls are placed in the user interface.
Note that in this example, the order of the controls is also changed.
Link to XForms Application
[edit | edit source]Load Datatypes from XML Schema
XML Schema diagram
[edit | edit source]The following is an XML Schema diagram with data types visible. Note that the data type is displayed directly under the data element. This diagram also shows optional data elements using a dashed line and the cardinality of the data elements.
Sample Program
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<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>Loading data from an XML Schema file</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
xf|input {
display: table-row;
line-height: 2em;
}
xf|label {
display: table-cell;
text-align: right;
font-family: Ariel, Helvetica, sans-serif;
font-weight: bold;
font-size: small;
padding-right: 5px;
width: 150px;
}
*:required {
background-color: yellow;
}
*:invalid {
background-color: pink;
}
</style>
<xf:model id="test" schema="data-types.xsd">
<xf:instance src="instance-data.xml"/>
</xf:model>
</head>
<body>
<xf:group model="test" nodeset="/Data">
<xf:input ref="date">
<xf:label>Date:</xf:label>
</xf:input>
<xf:input ref="string-required">
<xf:label>Required String:</xf:label>
</xf:input>
<xf:input model="test" ref="string-optional">
<xf:label>Optional String:</xf:label>
</xf:input>
<xf:repeat nodeset="string-unbounded">
<xf:input ref=".">
<xf:label>Unbounded String:</xf:label>
</xf:input>
</xf:repeat>
<xf:input ref="integer">
<xf:label>Integer:</xf:label>
</xf:input>
<xf:input ref="positive-integer">
<xf:label>Positive Integer:</xf:label>
</xf:input>
<xf:input ref="short">
<xf:label>Short:</xf:label>
</xf:input>
<xf:input ref="byte">
<xf:label>Byte:</xf:label>
</xf:input>
<xf:input ref="unsignedByte">
<xf:label>Unsigned Byte:</xf:label>
</xf:input>
<xf:input ref="boolean">
<xf:label>Boolean:</xf:label>
</xf:input>
</xf:group>
</body>
</html>
XML Schema
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Data">
<xs:annotation>
<xs:documentation>A listing of 10 XML Schema data types</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="date" type="xs:date"/>
<xs:element name="string-required" type="xs:string"/>
<xs:element name="string-optional" type="xs:string" minOccurs="0"/>
<xs:element name="string-unbounded" type="xs:string" maxOccurs="unbounded"/>
<xs:element name="integer" type="xs:integer"/>
<xs:element name="positive-integer" type="xs:positiveInteger"/>
<xs:element name="short" type="xs:short"/>
<xs:element name="byte" type="xs:byte"/>
<xs:element name="unsignedByte" type="xs:unsignedByte"/>
<xs:element name="boolean" type="xs:boolean"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
XML Instance
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML instance file-->
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="data-types.xsd">
<date>2006-09-21</date>
<string-required>The quick brown fox jumped over the lazy dog.</string-required>
<string-optional>This string is optional.</string-optional>
<string-unbounded>One of many.</string-unbounded>
<string-unbounded>Two of many.</string-unbounded>
<string-unbounded>Three of many.</string-unbounded>
<integer>-123</integer>
<positive-integer>2</positive-integer>
<short>4096</short>
<byte>127</byte>
<unsignedByte>255</unsignedByte>
<boolean>true</boolean>
</Data>
Testing
[edit | edit source]One of the ways to test if the data types are loaded correctly from the XML Schema file is to attempt to enter an invalid value of a specific data type. XForms should automatically check to see if the input field meets the data requirements specified in the XML Schema file.
For example in the positive integer fields you can attempt to enter a "-1". After you do this and enter a "tab" the background of the form should display in pink as a warning. This is how the screen should look:
The way you display invalid controls is controled by the following line in the CSS file:
*:invalid { background-color: red; }
This is known as a pseudo element. Although there are no data elements called "invalid", XForms just adds this property to each input control and the style sheet then adds whatever properties you give it in the style sheet.
Discussion
[edit | edit source]This program also uses a CSS to display the data elements.
Known bugs
[edit | edit source]Note that under the bindings do not work if there is no sample instance data.
In addition to this section, it may not be supported in other Xform platforms. Tested in XSLTForms, it does not work, with latest version as of 06/09/10 Used FormFaces, it worked, but could not render the css correctly.
There are also cross-browser compatibility issues as well.
References
[edit | edit source]http://betterform.wordpress.com/using-schema-datatypes/ betterForm inline schema types
Validate
This program demonstrates how to validate an instance document using an XML Schema. This is typically done before a document is submitted to a web service.
Sample Code
[edit | edit source]To be done...
Discussion
[edit | edit source]
Validate with schema types
Motivation
[edit | edit source]You would like to use a library of XML Schema simple types with restrictions to validate your form.
Notice
[edit | edit source]Most type validation with the exception of the most simple types does not currently work under the FireFox extension.
Sample Program sample.xhtml
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:ftype="http://www.example.com/my-file-types">
<head>
<title>Validate Postal Codes</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
xf|input {
display: table-row;
line-height: 2em;
}
xf|label {
display: table-cell;
text-align: right;
font-family: Arial, Helvetica, sans-serif;;
font-weight: bold;
padding-right: 5px;
width: 150px;
}
*:required {
background-color: yellow;
}
*:invalid {
background-color: pink;
}
</style>
<xf:model schema="schema.xsd">
<xf:instance src="instance.xml" />
<xf:bind id="zip" required="true()" type="ftype:zipType" nodeset="ftype:zip" />
<xf:bind id="zip2" required="true()" type="ftype:zip2Type" nodeset="ftype:zip2" />
</xf:model>
</head>
<body>
<xf:input bind="zip" incremental="true">
<xf:label>Zip Code: </xf:label>
<xf:hint>Validation is not correctly specified for this field</xf:hint>
<xf:alert>The 'Zip Code' failed to validate!</xf:alert>
</xf:input>
<xf:input bind="zip2" incremental="true">
<xf:label>Zip Code 2: </xf:label>
<xf:hint>Validation is correctly specified for this field</xf:hint>
<xf:alert>
<xf:output value="concat('The &quot;', name(), '&quot; failed to validate!')" />
</xf:alert>
</xf:input>
</body>
</html>
Example XML Schema File schema.xsd
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ftype="http://www.example.com/my-file-types"
targetNamespace="http://www.example.com/my-file-types"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:annotation>
<xs:documentation>Test XML Schema</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="zip" type="ftype:zipType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="zipType">
<xs:restriction base="xs:string">
<!-- bad pattern: matches any sequence of 5 digits, even if there are more digits or non-numeric. -->
<xs:pattern value="\d{5}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="zip2Type">
<xs:restriction base="xs:string">
<!-- good pattern: matches only 5 digits, nothing extra -->
<xs:pattern value="^\d{5}$"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Sample instance document instance.xml
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="http://www.example.com/my-file-types">
<zip>12345</zip>
<zip2>12345</zip2>
</data>
Discussion
[edit | edit source]
Facet Validation
Motivation
[edit | edit source]XML Schemas contain a large amount of data element constraint information other than just the data type. These restrictions on a specific data type are called "facets". Different data types have different types of facets. For example strings may have minimum and maximum length values and integers may have minimum and maximum numeric values.
This program demonstrates how XForms can validate a data set based on the facets within and XML Schema.
Warnings
[edit | edit source]Note: This program does not run under the FireFox 0.6 extension.
The X-Smiles browser was used to demonstrate this program.
Screen Image
[edit | edit source]This screen image was taken from the X-Smiles implementation of XForms.
Note that the second field is not at least three characters long so the field is invalid and the background it set to pink according to the CSS style for invalid fields.
XML Schema (schema.xsd)
[edit | edit source]Here is a simple XML Schema with four strings. The first one is only allowed to be two characters long. The second must have a minimum length of three characters. The third string must not be over five characters long and the fourth one must be between five and seven characters long to be valid.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Data">
<xs:annotation>
<xs:documentation>A demonstration of XML Schema string facets.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="string-length-2">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="string-min-3">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="string-max-5">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="string-5-7">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="5"/>
<xs:maxLength value="7"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Sample Instance (instance.xml)
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<Data
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="schema.xsd">
<string-length-2>MN</string-length-2>
<string-min-3>abcd</string-min-3>
<string-max-5>abcd</string-max-5>
<string-5-7>abcdef</string-5-7>
</Data>
Sample Program
[edit | edit source]The following program loads both the XML Schema and initial instance data from two external files (schema.xsd and instance.xml). The initial data in this example is valid but you can change the data to test the validation.
<?xml version="1.0" encoding="UTF-8"?>
<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>Facet validation using X-Smiles.</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
xf|input {
/* display: table-row; */
line-height: 2em;
}
xf|label {
/* display: table-cell; */
text-align: right;
font-family: Ariel, Helvetica, sans-serif;
font-weight: bold;
font-size: medium;
padding-right: 5px;
width: 130px;
}
*:required {
background-color: yellow;
}
*:invalid {
background-color: pink;
}
</style>
<xf:model id="test" schema="schema.xsd">
<xf:instance src="instance.xml" />
</xf:model>
</head>
<body>
<xf:group model="test" nodeset="/Data">
<p>
<xf:input ref="string-length-2" incremental="true">
<xf:label>Length exactly 2:</xf:label>
</xf:input>
</p>
<p>
<xf:input ref="string-min-3" incremental="true">
<xf:label>Length 3 or more:</xf:label>
</xf:input>
</p>
<p>
<xf:input ref="string-max-5" incremental="true">
<xf:label>Length 5 or less:</xf:label>
</xf:input>
</p>
<p>
<xf:input ref="string-5-7" incremental="true">
<xf:label>Length 5 to 7:</xf:label>
</xf:input>
</p>
</xf:group>
</body>
</html>
The two lines that load the XML Schema and instance data are:
<xf:model id="test" schema="schema.xsd">
<xf:instance src="instance.xml" />
</xf:model>
Also note that the input fields have the incremental attribute set to true. This allows character-by-character validation. The form is revalidated with each key stroke.
Discussion
[edit | edit source]
SVG
Motivation
[edit | edit source]You want to dynamically load and render SVG.
Sample Program
[edit | edit source]<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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:svg="http://www.w3.org/2000/svg">
<head>
<title>SVG Browser</title>
<style type="text/css">
#svgimg .xforms-value {
width: 400px;
min-width: 400px;
height: 400px;
min-height: 400px;
}
</style>
<xf:model>
<xf:instance id="current">
<current xmlns=""/>
</xf:instance>
<xf:instance id="names">
<names xmlns="">
<name fname="mozilla.svg">Mozilla</name>
<name fname="wii.svg">Wii</name>
<name fname="duke.svg">Duke</name>
<name fname="git.svg">Git</name>
<name fname="cartman.svg">Cartman</name>
<name fname="tiger.svg">Tiger</name>
<name fname="gcheck.svg">GCheck</name>
<name fname="pencil.svg">Pencil</name>
<name fname="python.svg">Python</name>
<name fname="ietf.svg">IETF</name>
<name fname="osgr_pie.svg">OSGR Pie</name>
</names>
</xf:instance>
<xf:instance id="inlinesvg">
<svg xmlns='http://www.w3.org/2000/svg'/>
</xf:instance>
<xf:submission id="loadsvg"
method="get"
replace="instance"
instance="inlinesvg"
serialization="none"
mode="synchronous">
<xf:resource value="concat('svg/',.)"/>
</xf:submission>
<xf:action ev:event="xforms-ready">
<xf:setvalue ref="." value="instance('names')/name[1]/@fname"/>
<xf:send submission="loadsvg"/>
</xf:action>
</xf:model>
</head>
<body>
<h1>SVG Browser</h1>
<xf:select1 ref="." appearance="minimal" incremental="true">
<xf:label>Select SVG: </xf:label>
<xf:itemset nodeset="instance('names')/name">
<xf:label ref="."/>
<xf:value ref="@fname"/>
</xf:itemset>
<xf:send ev:event="xforms-value-changed" submission="loadsvg"/>
</xf:select1>
<xf:trigger>
<xf:label>Next</xf:label>
<xf:setvalue ev:event="DOMActivate"
ref="."
value="if(
instance('names')/name[
preceding-sibling::name[1]/@fname
= current()
],
instance('names')/name[
preceding-sibling::name[1]/@fname
= current()
]/@fname,
instance('names')/name[1]/@fname)"/>
</xf:trigger>
<br/>
<xf:output id="svgimg"
value="xf:serialize(instance('inlinesvg'))"
mediatype="image/svg+xml"/>
</body>
</html>
Credits
[edit | edit source]This was created by Alain Couthures on the XSLTForms mailing list. A working copy can currently be found on the AgenceXML web site.
Dynamically Load JavaScript
Motivation
[edit | edit source]Sometime XForms data elements don't do everything you need. This is especially true for exception handling. When this happens you can dynamically load a JavaScript program to handle the required functionality.
This example will use the XForms load element. But unlike most JavaScript functions, it will not be loaded into the browser until it is needed.
Sample Program
[edit | edit source]Here is an example of using the load element within an XForms trigger:
First you will need a small JavaScript funtion to test like the following:
<script type="text/javascript">
var MyJavaScript=function(){
alert('Hello From JavaScript');
}
</script>
Then you can call this JavaScript function using the Load function within a trigger:
<xf:trigger>
<xf:label>Run JavaScript</xf:label>
<xf:action ev:event="DOMActivate">
<xf:load resource="javascript:MyJavaScript()" />
........
</xf:action>
</xf:trigger>
You can also pass data from an XForms instance by using the following example:
function myjavascriptfunction(id) {
// We get the instance element
var instanceElement = document.getElementById(id);
if (instanceElement!=null) {
// XForms exposes the retrieval of the instance document from the model element which *should*
// be the parent for the instance element.
var instance = instanceElement.parentNode.getInstanceDocument(id);
}
}
When the user selects this trigger the JavaScript function my-javascript-function will be dynamically loaded into the XForm application and executed.
References
[edit | edit source]This program was inspired by the following example posted by Nicholas Chase, a Freelance writer with Backstop Media.
The link is here: IBM XForms Tip Call JavaScript
Pie Chart
Motivation
[edit | edit source]You want to use range controls to interactively change a drawing such as a pie chart. In this case we use a JavaScript library that modifies an SVG image. The data for the pie chart is kept in an instance in the model.
Screen Image
[edit | edit source]Link to Working XForms Application
[edit | edit source]XForms Example of Dynamic Labels
Sample Program
[edit | edit source]<?xml version="1.0" encoding="iso-8859-1"?>
<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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<head>
<link rel="stylesheet" href="pie-chart.css" type="text/css" />
<title>Pie Chart with XForms Range Controls</title>
<script type="text/javascript" src="pie-chart.js" />
<xf:model id="theModel">
<xf:instance id="theData">
<charts xmlns="">
<piechart>
<wedge01>120</wedge01>
<wedge02>120</wedge02>
<wedge03>120</wedge03>
<wedge04>0.00</wedge04>
</piechart>
</charts>
</xf:instance>
<!-- Section 2 -->
<xf:bind nodeset="/charts/piechart/wedge01" type="xsd:decimal" />
<xf:bind nodeset="/charts/piechart/wedge02" type="xsd:decimal" />
<xf:bind nodeset="/charts/piechart/wedge03" type="xsd:decimal" />
<xf:bind nodeset="/charts/piechart/wedge04" type="xsd:decimal" />
<xf:bind nodeset="/charts/piechart/wedge04" calculate="/charts/piechart/wedge01 + /charts/piechart/wedge02 + /charts/piechart/wedge03" />
</xf:model>
</head>
<body onload="showChart('chart')">
<h1>Pie Chart with XForms Range Controls</h1>
<div id="chart">
<!-- Placeholder for chart. Javascript will load here. -->
</div>
<br />
<xf:range ref="/charts/piechart/wedge01" id="s2l1" start="0" end="360" incremental="true">
<xf:label>Red:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:load resource="javascript:updateChart('chart')" />
</xf:action>
</xf:range>
<xf:range ref="/charts/piechart/wedge02" start="0" end="360" incremental="true">
<xf:label>Orange:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:load resource="javascript:updateChart('chart')" />
</xf:action>
</xf:range>
<xf:range ref="/charts/piechart/wedge03" start="0" end="360" incremental="true">
<xf:label>Yellow:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:load resource="javascript:updateChart('chart')" />
</xf:action>
</xf:range>
</body>
</html>
Discussion
[edit | edit source]This example a nice clean way to interactively change a value just using the mouse. No keyboard required. Here is the sample for the first range control:
<xf:range ref="/charts/piechart/wedge01" start="0" end="360" incremental="true">
<xf:label>Red:</xf:label>
<xf:action ev:event="xforms-value-changed">
<xf:load resource="javascript:updateChart('chart')" />
</xf:action>
</xf:range>
This is an example of how an instance document can be used as the interface to an external component in a form. You just have to put the data in the instance and tell the application to get the data.
Credits
[edit | edit source]This example was originally inspired by the 1040 tax form example on the Mozilla web site. The JavaScript for drawing the pie chart was taken from that example.
Google Charts
Motivation
[edit | edit source]You want to use a web service to create charts.
Method
[edit | edit source]In this example we will use the Google Chart web service: *. Users are each allowed to generate up to 50,000 charts per day.
Parameters
[edit | edit source]The Google Chart application takes several parameters from the URL. For a simple Pie Chart these might include:
http://chart.apis.google.com/chart? cht=p &chd=t:10,20,30,40,20 &chl=Amount|Indicator|Code|Date|Text &chs=400x300
Where:
http://chart.apis.google.com/chart?
- is the Chart API's base URL
The ampersand (&) separates parameters.
cht=p
is a code for the chart's type. For example p=2D Pie Chart and p3-3D Pie Chart
chd=t:10,20,30,40
is the chart's data using t format (t:10,20,30) or s format where (s:) a=1 and z=26
chs=400x300
- is the chart's size in pixels.
chl
=Amount|Indicator|Code|Date|Text are the labels for the Pie Chart.
Our next step is to put these REST parameters into an XForms instance and hook the instance up to input controls.
Pie Chart Parameters in XML instance
[edit | edit source]Here are the parameters for a piechart type, data, label and size information.
<xf:instance id="chart-params" xmlns="">
<data>
<cht/>
<chd/>
<chl/>
<chs/>
</data>
</xf:instance>
Chart Submission
[edit | edit source]We will submit our XForms data to the server using the following submission statement.
<xf:submission id="get-chart"
method="get" action="http://chart.apis.google.com/chart"
separator="&" ref="instance('chart-params')" replace="all"/>
Binding Rules
[edit | edit source]Here is a sample input form for chart parameters:
Here is a sample output chart generated form this application.
Sample XForms Application on Google Code
[edit | edit source]Sample Program
[edit | edit source]<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>Google Pie Chart Demo</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Helvetica, sans-serif}
/* This line ensures all the separate input controls appear on their own lines */
xf|input, xf|select1 {display:block; margin:5px 0;}
/* this puts the labels in 200px columns and right aligns them */
xf|input > xf|label, xf|select1 > xf|label
{text-align:right; padding-right:10px; width:200px; float:left; text-align:right;}
.xf-value {width: 250px}
</style>
<xf:model>
<xf:instance id="chart-params" xmlns="">
<data>
<cht>p</cht>
<chs>400x200</chs>
<chd>t:1,2,60,40,2</chd>
<chl>Amount|Indicators|Code|D|Text</chl>
</data>
</xf:instance>
<xf:submission id="get-chart" action="http://chart.apis.google.com/chart" method="get"
separator="&" ref="instance('chart-params')" replace="all"/>
<!-- 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>Google PieChart Demo</h3>
<xf:select1 ref="cht" id="field-1">
<xf:label>Chart Type: </xf:label>
<xf:item>
<xf:label>Pie Chart - flat</xf:label>
<xf:value>p</xf:value>
</xf:item>
<xf:item>
<xf:label>Pie Chart - 3D</xf:label>
<xf:value>p3</xf:value>
</xf:item>
</xf:select1>
<xf:input ref="chd">
<xf:label>Data: (t:5,10,20): </xf:label>
</xf:input>
<xf:input ref="chl">
<xf:label>Labels: (A|B) </xf:label>
</xf:input>
<xf:submit submission="get-chart">
<xf:label>Create Chart</xf:label>
</xf:submit>
</body>
</html>
Discussion
[edit | edit source]This is actually one of the most simple applications. Google Charts has five chart types and hundreds of combinations of parameters. The Chart Types are (cht)
- Line charts
- Bar charts
- Pie charts
- Venn diagrams
- Scatter plots
One way to test these is to generate a variety of charts with some sample XForms.
Venn Diagram
Motivation
[edit | edit source]You want to interactively change Venn Diagram parameters.
Method
[edit | edit source]Use XForms range controls to change values in a form. Use the bind to concatenate input parameters. Use the incremental attribute to allow the user to see the changes as the range controls change. Sending a submit will alter the Venn Diagram REST parameters.
Screen Image of User Interface
[edit | edit source]Output of Call to Google Charts
[edit | edit source]Link to Executable Example
[edit | edit source]Program Code
[edit | edit source]<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>Google Venn Diagram</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Helvetica, sans-serif}
/* This line ensures all the separate input controls appear on their own lines */
xf|input, xf|range, xf|output {display:block; margin:5px 0;}
/* this puts the labels in120px columns and right aligns them */
xf|input > xf|label, xf|range > xf|label, xf|output > xf|label
{text-align:right; padding-right:10px; width:120px; float:left; text-align:right;}
.xf-value {width: 150px}
</style>
<xf:model>
<xf:instance id="chart-params" xmlns="">
<data>
<cht>v</cht>
<chs>400x400</chs>
<chd/>
<chdl/>
</data>
</xf:instance>
<!-- temp variables that are concated together to create the parameter -->
<xf:instance xmlns="" id="tmp">
<data>
<sa>15</sa>
<sb>20</sb>
<sc>25</sc>
<ab>10</ab>
<ac>12</ac>
<bc>15</bc>
<abc>5</abc>
<la>A</la>
<lb>B</lb>
<lc>C</lc>
</data>
</xf:instance>
<xf:bind nodeset="instance('tmp')/sa" type="xs:integer"/>
<xf:bind nodeset="instance('tmp')/sb" type="xs:integer"/>
<xf:bind nodeset="instance('tmp')/sc" type="xs:integer"/>
<xf:bind nodeset="instance('tmp')/ab" type="xs:integer"/>
<xf:bind nodeset="instance('tmp')/ac" type="xs:integer"/>
<xf:bind nodeset="instance('tmp')/bc" type="xs:integer"/>
<xf:bind nodeset="instance('tmp')/abc" type="xs:integer"/>
<xf:bind nodeset="instance('chart-params')/chd" calculate="concat( 't:',
instance('tmp')/sa, ',',
instance('tmp')/sb, ',',
instance('tmp')/sc, ',',
instance('tmp')/ab, ',',
instance('tmp')/ab, ',',
instance('tmp')/bc, ',',
instance('tmp')/abc
)"/>
<xf:bind nodeset="instance('chart-params')/chdl" calculate="concat(
instance('tmp')/la, '|',
instance('tmp')/lb,'|',
instance('tmp')/lc
)"/>
<xf:submission id="get-chart" action="http://chart.apis.google.com/chart" method="get"
separator="&" ref="instance('chart-params')" replace="all"/>
<!-- 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>Google Venn Diagram Demo</h3>
<xf:range ref="instance('tmp')/sa" start="2" end="30" step="1" incremental="true">
<xf:label>Size A: </xf:label>
</xf:range>
<xf:range ref="instance('tmp')/sb" start="2" end="30" incremental="true">
<xf:label>Size B: </xf:label>
</xf:range>
<xf:range ref="instance('tmp')/sc" start="2" end="30" incremental="true">
<xf:label>Size C: </xf:label>
</xf:range>
<xf:range ref="instance('tmp')/ab" start="0" end="20" incremental="true">
<xf:label>AB Distance: </xf:label>
</xf:range>
<xf:range ref="instance('tmp')/ac" start="0" end="20" incremental="true">
<xf:label>AC Distance: </xf:label>
</xf:range>
<xf:range ref="instance('tmp')/bc" start="0" end="20" incremental="true">
<xf:label>BC Distance: </xf:label>
</xf:range>
<xf:range ref="instance('tmp')/abc" start="0" end="20" incremental="true">
<xf:label>ABC Overlap: </xf:label>
</xf:range>
<xf:output ref="chd">
<xf:label>Data:</xf:label>
</xf:output>
<xf:input ref="instance('tmp')//la">
<xf:label>Label A: </xf:label>
</xf:input>
<xf:input ref="instance('tmp')/lb">
<xf:label>Label B: </xf:label>
</xf:input>
<xf:input ref="instance('tmp')/lc">
<xf:label>Label C: </xf:label>
</xf:input>
<xf:output ref="instance('chart-params')/chd">
<xf:label>Distance Data:</xf:label>
</xf:output>
<xf:output ref="instance('chart-params')/chdl">
<xf:label>Labels:</xf:label>
</xf:output>
<xf:submit submission="get-chart">
<xf:label>Create Venn Diagram</xf:label>
</xf:submit>
</body>
</html>
Discussion
[edit | edit source]
Supply and Demand
Motivation
[edit | edit source]You want to create a simple illustration of a concept using a dynamic graph. You want to use a range control to change in input and see the impact of that change on an output.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]This is not working yet with the range control. I wrote it with just SVG and JavaScript and I am in the process of porting it to XForms. I also need to use CSS to clean up the markup.
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="300" height="450" onload="OnLoadEvent(evt)"> <defs> <g id="arrowMarker"> <g stroke="black" stroke-width="1"> <line x1="6" y1="-2" x2="0" y2="0"/> <line x1="6" y1="+2" x2="0" y2="0"/> </g> </g> <marker id="startMarker" markerWidth="48" markerHeight="24" viewBox="-4 -4 25 5" orient="auto" refX="0" refY="0" markerUnits="strokeWidth"> <g> <use xlink:href="#arrowMarker" transform="rotate(180)" stroke-width="1" stroke="black"/> </g> </marker> </defs> <!-- Title --> <text x="125" y="30" style="text-anchor:middle; font-family:Ariel-Narrow; font-weight:bold; font-size:18">Price and Demand</text> <!-- bounding box including all elements --> <rect x="10" y="10" width="250" height="430" style="stroke:black; stroke-width:2; fill:none"/> <!-- all drawing is done with the origin being at (0,0) --> <!-- graph itself --> <g transform="translate(30 40)"> <!-- vertical price axis --> <line x1="0" x2="0" y1="200" y2="0" style="fill:none;stroke:black;stroke-width:1;" marker-end="url(#startMarker)"/> <text x="15" y="10">P</text> <!-- horizontal axis quantity--> <line x1="0" x2="200" y1="200" y2="200" style="fill:none;stroke:black;stroke-width:1;" marker-end="url(#startMarker)"/> <text x="205" y="205">Q</text> <!-- fixed demmand curve --> <path id="demmand_curve" style="stroke:red; stroke-width:3" d="M0,0 200,200"/> <text x="120" y="-10" transform="rotate(45)">Demand</text> <!-- initial value of price --> <circle id="newPrice" cx="0" cy="100" r="4" style="stroke:blue; fill:blue"/> <text id="priceLabel" x="163" y="20" style="text-anchor:end">Input: Price =</text> <text id="priceText" x="163" y="20">100</text> <text id="quantityLabel" x="163" y="35" style="text-anchor:end">Output: Quantity =</text> <text id="quantityText" x="163" y="35">100</text> <line id="vertLine" x1="100" y1="100" x2="100" y2="200" style="stroke-dasharray: 1, 4;stroke:black;stroke-width:1; "/> <line id="horizLine" x1="0" y1="100" x2="100" y2="100" style="stroke-dasharray: 1, 4;stroke:black;stroke-width:1; "/> <g id="explanation" transform="translate(0 260)"> <text x="10" y="0">Adjust price by moving the slider.</text> <text x="0" y="50">Note that as the input (price) changes.</text> <text x="10" y="65">the quantity sold also changes.</text> <text x="0" y="90">At high prices a low quantity is sold.</text> <text x="0" y="110">At low prices a high quantity is sold.</text> </g> <g id="slider" transform="translate(0 220)" xoffset="30"> <rect x="0" y="0" width="210" height="20" style="fill:#c0c0c0"/> <line style="stroke:black;stroke-width:2;" x1="5" y1="6" x2="205" y2="6"/> <line style="stroke:white;stroke-width:2;" x1="5" y1="8" x2="205" y2="8"/> <path style="stroke:black;fill:none;" d="M5,16 5,20 M25,16 25,20 M45,16 45,20 M65,16 65,20 M85,16 85,20 M105,16 105,20 M125,16 125,20 M145,16 145,20 M165,16 165,20 M185,16 185,20 M205,16 205,20"/> <g id="thumb" transform="translate(100 0)"> <path style="stroke:none;fill:#c0c0c0;" d="M1,2 1,12 5,15 9,12 9,2 Z"/> <path style="stroke:white;fill:none;" d="M9,1 1,1 1,11"/> <path style="stroke:black;fill:none;" d="M5,16 10,12 10,2"/> </g> <g id="explanation" transform="translate(20 230)"> <text x="0" y="0">Note that as the input (price) moves, the quantity sold changes.</text> <text x="0" y="20">At high prices a low quantity is sold.</text> <text x="0" y="40">At low prices a high low quantity is sold.</text> </g> </g> </g> <script><![CDATA[ // == Slider object based on version by Dr. Stefan Goessner at http://www.mecxpert.de/svg/slider.html var slider=null, thumb=null, sliderActive = false; var newPrice=null, priceText=null, quantityText=null, vertLine=null, horizLine=null; // ----------------------------------------------------------- function SliderDown(event) { sliderActive = true; } function SliderUp(event) { sliderActive = false; // window.status = "slider is inactive"; } function SliderMove(event) { var value = event.getClientX() - parseFloat(slider.getAttribute("xoffset")) - 4; if (sliderActive && value > 0 && value < 200) { thumb.setAttribute("transform", "translate(" + (value) + " 0)"); SliderCallback(value); } } function SliderClick(event) { var value = event.getClientX() - parseFloat(slider.getAttribute("xoffset")) - 4; if (value > 0 && value < 200) { thumb.setAttribute("transform", "translate(" + (value) + " 0)"); SliderCallback(value); } } function SliderCallback(val) { // this is where we change the values newPrice.setAttribute("cy", val); horizLine.setAttribute("y1", val); horizLine.setAttribute("y2", val); horizLine.setAttribute("x2", val); vertLine.setAttribute("x1", val); vertLine.setAttribute("x2", val); vertLine.setAttribute("y1", val); priceText.firstChild.nodeValue=(200-val); quantityText.firstChild.nodeValue=(val); //= Math.round((val*1000)/1000); window.status = "price is " + (val); } function OnLoadEvent(event) // called, when svg file is loaded (s. onLoad=..) .. { var doc = event.getTarget() != null ? event.getTarget().getOwnerDocument() : null; if (doc != null) { slider = doc.getElementById("slider"); thumb = doc.getElementById("thumb"); newPrice = doc.getElementById("newPrice"); priceText = doc.getElementById("priceText"); quantityText = doc.getElementById("quantityText"); vertLine = doc.getElementById("vertLine"); horizLine = doc.getElementById("horizLine"); slider.addEventListener("mousedown", SliderDown, false); slider.addEventListener("mouseup", SliderUp, false); slider.addEventListener("mousemove", SliderMove, false); slider.addEventListener("click", SliderClick, false); } } ]]></script> </svg> <header> <xf:model> <xf:instance xmlns=""> <data> <price>100</price> </data> </xf:instance> </xf:model> </header> <body> <xf:range ref="price" start="0" end="200" step="1"> <xf:label>Price: </xf:label> </xf:range> <xf:output ref="price" > <xf:label>Price: </xf:label> </xf:output> </body> </html>
Discussion
[edit | edit source]
Graph Viewer
Motivation
[edit | edit source]Sometimes you need to have a form edit data structures that are recursive. In other words: a structure that references itself.
This example has nodes that have links. These links in turn point back to nodes. This is an example of a self-referential data structure. This is common when manipulating graphs. Workflow systems frequently use these structures.
Link to Working Example
[edit | edit source]XML Schema
[edit | edit source]Here is a sample XML Schema with a recursive data type (a data type that includes an instance of itself):
graph.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Graph">
<xs:annotation>
<xs:documentation>Comment describing your root element</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="graph-name">
<xs:annotation>
<xs:documentation>The name of the graph</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="graph-description" minOccurs="0"/>
<xs:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>A node that has zero or more links</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="nodeType">
<xs:annotation>
<xs:documentation>A node in a graph with 0 to n links</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="node-id">
<xs:annotation>
<xs:documentation>node identifier</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="links" type="linkType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="linkType">
<xs:annotation>
<xs:documentation>A link from one node to another.</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="link-id">
<xs:annotation>
<xs:documentation>link identifier</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="node" type="nodeType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Instance Document
[edit | edit source]<Graph>
<graph-name>USA</graph-name>
<graph-description>Example of graph with states, counties, cities and neighborhoods.</graph-description>
<node>
<node-id>usa</node-id>
<links>
<link-id>states-in-the-us</link-id>
<node>
<node-id>california</node-id>
</node>
<node>
<node-id>kansas</node-id>
</node>
<node>
<node-id>illinois</node-id>
</node>
<node>
<node-id>iowa</node-id>
</node>
<node>
<node-id>minnesota</node-id>
<links>
<link-id>counties-in-minnesota</link-id>
<node>
<node-id>carver</node-id>
</node>
<node>
<node-id>dakota</node-id>
</node>
<node>
<node-id>hennepin</node-id>
<links>
<link-id>cities in hennpin county</link-id>
<node>
<node-id>bloomington</node-id>
</node>
<node>
<node-id>minneapolis</node-id>
</node>
<node>
<node-id>richfield</node-id>
</node>
<node>
<node-id>st-louis-park</node-id>
<links>
<link-id>neighborhoods-in-st-louis-park</link-id>
<node>
<node-id>aquila</node-id>
</node>
<node>
<node-id>cobblecrest</node-id>
</node>
<node>
<node-id>elmwood</node-id>
</node>
</links>
<!-- neighborhoods-in-st-louis-park -->
</node>
</links>
<!-- cities-in-hennepin county -->
</node>
<node>
<node-id>ramsey</node-id>
<links>
<link-id>cities in ramsey county</link-id>
<node>
<node-id>eagan</node-id>
</node>
<node>
<node-id>st-paul</node-id>
</node>
</links>
</node>
</links>
<!-- counties-in-minnesota -->
</node>
<node>
<node-id>new-york</node-id>
</node>
</links>
<!-- states-in-the-us -->
</node>
</Graph>
XForms Example
[edit | edit source]This example allows you to view a graph of geographic regions.
Make sure to copy and past from the edit view of cookbook since the greater than symbols get converted.
<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 Graph Viewer</title>
<style type="text/css">
body { font-family: Verdana, Helvetica, sans-serif }
output {font-size: 10pt}
.bold {font-weight: bold}
.indent {margin-left: 250px}
</style>
<xf:model>
<xf:instance xmlns="" id="saved-data" src="usa.xml" />
<xf:instance xmlns="" id="path">
<data>
<!-- set initial value to be the root node -->
<current-node-id>usa</current-node-id>
</data>
</xf:instance>
<xf:bind id="current-node-id" nodeset="instance('path')/current-node-id" />
<xf:submission id="save-to-file" method="put" action="usa.xml" replace="instance" instance="saved-data" />
</xf:model>
</head>
<body>
<h1>XForms Graph Viewer</h1>
<p>Example of viewing arbitrarily deep hierarchies with XForms v0.1</p>
<xf:input ref="graph-name">
<xf:label>Graph Name: </xf:label>
</xf:input>
<br />
<xf:textarea ref="graph-description">
<xf:label>Description: </xf:label>
</xf:textarea>
<br />
<br />
<xf:input bind="current-node-id" incremental="true">
<xf:label>Search for node id:</xf:label>
</xf:input>
<br />
<div class="bread-crumbs">
<p>Sample short-cuts:</p>
<xf:trigger>
<xf:label>usa</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="current-node-id" value="'usa'" />
</xf:action>
</xf:trigger>
->
<xf:trigger>
<xf:label>minnesota</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="current-node-id" value="'minnesota'" />
</xf:action>
</xf:trigger>
->
<xf:trigger>
<xf:label>hennepin</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="current-node-id" value="'hennepin'" />
</xf:action>
</xf:trigger>
->
<xf:trigger>
<xf:label>st-louis park</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="current-node-id" value="'st-louis-park'" />
</xf:action>
</xf:trigger>
</div>
<h3>Current Node</h3>
<xf:output ref="instance('path')/current-node-id" class="bold">
<xf:label>Current node id: </xf:label>
</xf:output>
<br/>
<xf:output ref="//node[node-id=instance('path')/current-node-id]/links/link-id" class="bold">
<xf:label>Link type: </xf:label>
</xf:output>
<!-- This is the critical line. Find all the nodes in the graph that have a node-id of the current-node-id -->
<xf:repeat nodeset="//node[node-id=instance('path')/current-node-id]/links/node" id="repeat-node1">
<xf:trigger class="indent">
<xf:label> <!-- the label on the button -->
<xf:output ref="node-id" />
</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('path')/current-node-id" value="instance('saved-data')//node[node-id=instance('path')/current-node-id]/links/node[position()=index('repeat-node1')]/node-id" />
</xf:action>
</xf:trigger>
</xf:repeat>
<h3>All Nodes:</h3>
<xf:repeat nodeset="//node" id="repeat-node2">
<xf:output ref="node-id">
<xf:label>Node Name: </xf:label>
</xf:output>
</xf:repeat>
<h3>Link Types:</h3>
<xf:repeat nodeset="//links" id="repeat-link">
<xf:output ref="link-id">
<xf:label>Link Name: </xf:label>
</xf:output>
</xf:repeat>
<xf:submit submission="save-to-file">
<xf:label>Save graph</xf:label>
</xf:submit>
</body>
</html>
Discussion
[edit | edit source]Most of this is straight-forward XForms code. But there is one very tricky line. This is when you click on a node listed in the list of links and you want to make the node you just selected the current node.
The trick is is to use the position() to match the index() value. When the position matches the index you can set the current-node-id equal to this node.
<xf:setvalue ref="instance('path')/current-node-id" value="instance('saved-data')//node[node-id=instance('path')/current-node-id]/links/node[position()=index('repeat-node1')]/node-id" />
Thanks to Fraser for the tip!
Event Logger
Motivation
[edit | edit source]You want to be able to see a record of events as they happen. This is a great way to learn about how XML Events work.
Method
[edit | edit source]We create an instance and add a element to that for each event.
Screen Image
[edit | edit source]Link to Example
[edit | edit source]Sample Code
[edit | edit source]<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>Demo of XForms Event Logging</title>
<style type="text/css" media="screen">
body {font-family: Helvetica, sans-serif;}
#log {
font-size: 8pt;
color: SlateGray;
background-color: lavender;
border: 1px solid SlateGray;
}
</style>
<xf:model>
<xf:instance id="my-form">
<data xmlns="">
<element1/>
<element2/>
<element3/>
</data>
</xf:instance>
<!-- this is were we log 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:insert nodeset="instance('log')/event" at="last()" position="after"/>
<xf:setvalue ref="instance('log')/event[last()]" value="'Set Focus on Field-1'" />
</xf:action>
</xf:model>
</head>
<body>
<h2>Demonstration of XForms Event Logging</h2>
<xf:input ref="instance('my-form')/element1" incremental="true" id="field-1">
<xf:label>Input 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="'DOMFocusIn in 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="'xforms-value-changed in input 1'" />
</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:action>
</xf:input>
<br/>
<xf:input ref="instance('my-form')/element2" incremental="true">
<xf:label>Input 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="'DOMFocusIn in 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="'xforms-value-changed in input 2'" />
</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 2'" />
</xf:action>
</xf:input>
<br/>
<xf:input ref="instance('my-form')/element3" incremental="true">
<xf:label>Input 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="'DOMFocusIn in 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="'xforms-value-changed in input 3'" />
</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 3'" />
</xf:action>
</xf:input>
<div id="log">
<p>Event Log</p>
<xf:repeat id="results-repeat" nodeset="instance('log')/event">
<xf:output ref="."/>
</xf:repeat>
</div>
</body>
</html>
Sample code 2
[edit | edit source]The above code doesn't work in the mozilla xforms plugin 0.8.5 with firefox 2.0.0.12 (it seems buggy dealing with instance). Try this code instead:
<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">
<!-- mozilla xforms 0.8.5, firefox 2.0.0.12
-->
<head>
<title>Demo of XForms Event Logging</title>
<style type="text/css">
body {font-family: Helvetica, sans-serif;}
#log {
font-size: 8pt;
color: SlateGray;
background-color: lavender;
border: 1px solid SlateGray;
}
</style>
<xf:model>
<xf:instance id="my-form">
<data xmlns="">
<element1/>
<element2/>
<element3/>
<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:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'Set Focus on Field-1'"/>
</xf:action>
</xf:model>
</head>
<body>
<h2>Demonstration of XForms Event Logging</h2>
<xf:input ref="/data/element1" incremental="true" id="field-1">
<xf:label>Input 1:</xf:label>
<xf:action ev:event="DOMFocusIn">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'DOMFocusIn in input 1'"/>
</xf:action>
<xf:action ev:event="xforms-value-changed">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'xforms-value-changed in input 1'"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'Out of input 1'"/>
</xf:action>
</xf:input>
<br/>
<xf:input ref="/data/element2" incremental="true">
<xf:label>Input 2:</xf:label>
<xf:action ev:event="DOMFocusIn">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'DOMFocusIn in input 2'"/>
</xf:action>
<xf:action ev:event="xforms-value-changed">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'xforms-value-changed in input 2'"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'Out of input 2'"/>
</xf:action>
</xf:input>
<br/>
<xf:input ref="/data/element3" incremental="true">
<xf:label>Input 3:</xf:label>
<xf:action ev:event="DOMFocusIn">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'DOMFocusIn in input 3'"/>
</xf:action>
<xf:action ev:event="xforms-value-changed">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'xforms-value-changed in input 3'"/>
</xf:action>
<xf:action ev:event="DOMFocusOut">
<xf:insert nodeset="/data/event" at="last()" position="after"/>
<xf:setvalue ref="/data/event[last()]" value="'Out of input 3'"/>
</xf:action>
</xf:input>
<div id="log">
<p>Event Log</p>
<xf:repeat id="results-repeat" nodeset="/data/event">
<xf:output ref="."/>
</xf:repeat>
</div>
</body>
</html>
Discussion
[edit | edit source]This uses the insert element to insert text into an event log.
Replace Tester
Motivation
[edit | edit source]You want to build a form that will allow you quickly test replacement regular expressions using XQuery's replace function.
Screen Image
[edit | edit source]Link to Working Application
[edit | edit source]Sample Program
[edit | edit source]<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:ev="http://www.w3.org/2001/xml-events" >
<head>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Ariel, Helvetica, san-serif}
/* 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 150px 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, xf|output > xf|label
{font-weight: bold;text-align:right; padding-right:10px; width:150px; float:left; text-align:right;}
/* make the input boxes a little wider */
.xf-value {width: 200px}
</style>
<xf:model>
<xf:instance id="request" xmlns="">
<data>
<input>abcdefghi</input>
<pattern>def</pattern>
<replacement>123</replacement>
</data>
</xf:instance>
<xf:instance id="response" xmlns="">
<data/>
</xf:instance>
<xf:submission id="submit" method="get" action="http://localhost:8080/exist/rest/db/test/replace/replace.xq" replace="instance" instance="response"
separator="&">
<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>
</xf:model>
</head>
<body>
<h1>XForms Replace Tester</h1>
<xf:input ref="input">
<xf:label>Input:</xf:label>
</xf:input>
<xf:input ref="pattern">
<xf:label>Pattern:</xf:label>
</xf:input>
<xf:input ref="replacement">
<xf:label>Replacement:</xf:label>
</xf:input>
<xf:switch>
<xf:case id="ready">
<xf:submit submission="submit">
<xf:label>Submit</xf:label>
</xf:submit>
<xf:submit submission="echo-test">
<xf:label>Echo Test</xf:label>
</xf:submit>
</xf:case>
<xf:case id="case-busy">
<p>Waiting for response...</p>
</xf:case>
<xf:case id="case-submit-error">
<p>The server has returned a submit error event.</p>
</xf:case>
<xf:case id="case-done">
<xf:output ref="instance('response')/replace-result/text()">
<xf:label>Result:</xf:label>
</xf:output>
</xf:case>
</xf:switch>
</body>
</html>
XQuery Replace Tester
[edit | edit source]If you are using eXist, just place this file on the server in the same folder as your XForms test driver.
In the example above I used a test folder on the localhost:
http://localhost:8080/exist/rest/db/test/replace/replace.xq
xquery version "1.0";
declare namespace exist = "http://exist.sourceforge.net/NS/exist";
declare namespace system="http://exist-db.org/xquery/system";
declare namespace request="http://exist-db.org/xquery/request";
declare option exist:serialize "method=xml media-type=text/xml indent=yes";
(: replace demo :)
let $input := request:get-parameter('input', '')
let $pattern := request:get-parameter('pattern', '')
let $replacement := request:get-parameter('replacement', '')
return
<results>
<input>{$input }</input>
<pattern>{$pattern}</pattern>
<replacement>{$replacement}</replacement>
<replace-result>{replace($input , $pattern, $replacement)}</replace-result>
</results>
Discussion
[edit | edit source]This shows that you can quickly built tools to teach yourself complex functions like regular expression handling. You can also use the XQuery match function with returns a true/false if the regular expression matches an input string.
There are two variations of this example that are interesting. The first is where you replace the input form with a large text area for doing global replacements of large blocks of text. The second is where you replace the patten input box with a selection list with common replacement patterns.
References
[edit | edit source]Examples of replacement functions can be found here:
Process Step Editor
Motivation
[edit | edit source]You want to create a process editor where a process is a series of steps that grow horizontally as you add steps to a process. You want to override the default behavior of items in an repeat to be added horizontally, not vertically.
Process
[edit | edit source]Use a repeat but add the following to your css file
/* Makes the repeated items get added to the right. */
.xf-repeat-item {display:inline;}
/* We MUST put this in to limit the width of the repeated item */
.xf-repeat-item .xf-value {width: 70px;}
Screen Image
[edit | edit source]Working XForms Application
[edit | edit source]Source Code
[edit | edit source]<?xml version="1.0" encoding="UTF-8"?>
<html 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="http://www.w3.org/1999/xhtml">
<head>
<title>Process Steps</title>
<link rel="stylesheet" type="text/css" href="local.css"/>
<xf:model>
<xf:instance xmlns="" id="process">
<data>
<activity>
<activity-name>Step 1</activity-name>
<activity-type-code>enrich</activity-type-code>
<webservice-id>ws111</webservice-id>
<ruleset-id>r111</ruleset-id>
<schema-id>s111</schema-id>
</activity>
<activity>
<activity-name>Step 2</activity-name>
<activity-type-code>validate</activity-type-code>
<webservice-id>ws222</webservice-id>
<ruleset-id>r222</ruleset-id>
<schema-id>s222</schema-id>
</activity>
<activity>
<activity-name>Step 3</activity-name>
<activity-type-code>check-ruleset</activity-type-code>
<webservice-id>ws333</webservice-id>
<ruleset-id>r333</ruleset-id>
<schema-id>schema333</schema-id>
</activity>
<activity>
<activity-name>Step 4</activity-name>
<activity-type-code>check-ruleset</activity-type-code>
<webservice-id>ws444</webservice-id>
<ruleset-id>r444</ruleset-id>
<schema-id>s444</schema-id>
</activity>
</data>
</xf:instance>
</xf:model>
</head>
<body>
<h1>Process Step Editor</h1>
<div class="process-steps">
<xf:label class="group-label">Process:</xf:label>
<xf:repeat nodeset="instance('process')/activity" id="activity-repeat">
<div class="activity" style="display:inline;">
<div class="activity-label">
<xf:input ref="activity-name" id="activity-name"/>
</div>
<xf:trigger>
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('process')/activity" at="index('activity-repeat')" position="after"/>
<xf:setvalue ref="instance('process')/activity[index('activity-repeat')]/activity-name" value="''"/>
<!-- should insert on the new row -->
<xf:setfocus control="activity-name"/>
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>-</xf:label>
<xf:delete nodeset="instance('process')/activity[index('activity-repeat')]" ev:event="DOMActivate"/>
</xf:trigger>
</div>
</xf:repeat>
</div>
<!-- this is always showing the selected activity-->
<div class="inspector">
<xf:label class="group-label">Activity Inspector:</xf:label>
<xf:repeat nodeset="instance('process')/activity[index('activity-repeat')=position()]" style="display:inline">
<xf:input ref="activity-name">
<xf:label>Step Name:</xf:label>
</xf:input>
<xf:select1 ref="activity-type-code">
<xf:label>Activity Type:</xf:label>
<xf:item>
<xf:label>Enrich</xf:label>
<xf:value>enrich</xf:value>
</xf:item>
<xf:item>
<xf:label>Validate</xf:label>
<xf:value>validate</xf:value>
</xf:item>
<xf:item>
<xf:label>Check Ruleset</xf:label>
<xf:value>check-ruleset</xf:value>
</xf:item>
</xf:select1>
<!-- <xf:group ref="instance('views')/ruleset-view"></xf:group> -->
<xf:input ref="webservice-id">
<xf:label>Enrichment Service ID:</xf:label>
</xf:input>
<xf:input ref="ruleset-id">
<xf:label>Ruleset ID:</xf:label>
</xf:input>
<xf:input ref="schema-id">
<xf:label>Validate with Schema ID:</xf:label>
</xf:input>
</xf:repeat>
</div>
</body>
</html>
CSS File
[edit | edit source]@namespace xf url("http://www.w3.org/2002/xforms");
body {
font-family: Helvetica, sans-serif;
}
.process-steps {
border: black 1px solid;
color: black; background-color: lightgreen;
padding: 18px 10px 14px 15px;
}
xf|label {
font-weight: bold;
}
.group-label {
position:relative;
text-align:left;
font-weight:bold;
font-size:12pt;
background-color: #D6D6DA;
top: -9px;
left: -9px;
-moz-border-radius: .3em;
padding: 3px;
border: solid black 1px;
}
.activity {
position: relative;
width: 250px;
padding: 8px; margin: 2px;
border: 1px solid blue;
background: PowderBlue;
/* the following only works under FireFox */
-moz-border-radius: 1em;
}
/* this makes the repeated items get added to the right */
xf|repeat {display: inline !important;}
.xf-repeat-item {display:inline !important;}
/* you MUST put this in to limit the width of the repeated item */
.xf-repeat-item .xf-value {width: 70px;}
.activity-label {
display: inline;
text-align: center;
}
/* the label in the center of an activity box */
.activity .xf-value {
background-color: white;
text-align: center;
}
/* make the plus/minus buttons larger */
.activity xf|trigger xf|label {font-weight: bold; font-size: 12pt;}
.inspector {
border: black 1px solid;
color: black; background-color: pink;
padding: 15px;
width: 400px;
}
/* Makes the labels right aligned in a 200px wide column that floats to the left of the input controls. */
.inspector xf|input > xf|label,
.inspector xf|select > xf|label,
.inspector xf|select1 > xf|label,
.inspector xf|textarea > xf|label
{text-align:right; padding-right:10px; width:200px; float:left; text-align:right;}
/* This line ensures all the separate label controls in the inspector appear on their own lines */
.inspector xf|input,
.inspector xf|select,
.inspector xf|select1,
.inspector xf|textarea
{display:block; margin:5px 0;}
Discussion
[edit | edit source]
Application Builder
Motivation
[edit | edit source]You want to create a form that captures the specifications of an application that manages data saved from a form.
Method
[edit | edit source]Many times the resources needed to create an application are very similar. Many applications need basic operations such as:
- Create a New Record
- Read (view) a Record
- Update a Record
- Delete a Record
- Search for Records
These applications (sometimes referred to as a CRUD application for Create, Read, Update, Delete) are created over and over and frequently a pattern emerges. This pattern can be used as the basis for a specification and we can then build an XForms application to capture that specification.
This example assumes that the user wants to do these operations on a simple form and guides the user through a series of questions. A series of defaults is assumed but the user is allowed to override these defaults when the requirements differ from the standard.
The phrase "convention over configuration" is frequently used to describe a series of built-in assumptions about the default behavior of an application. If the developer of the application knows these conventions a highly functional initial application can quickly be created.
This form starts asking a series of questions, some of which are input fields, some check boxes and some text descriptions. Some input fields are referenced later in the application using binding rules. These binding rules are the conventional behavior of the application.
After the application specification is complete a "Generate Application" function can be executed. This will take the application specification file and execute a series of scripts on the server. Here are a sample of some actions that can be taken by these server-side build scripts. In this example we are using terminology from native XML data stores with XQuery REST interfaces but there are similar actions for RDBMS stores
- Create Default Collections
- data collection for XForms instance data
- edit collection for XForms editors (any forms that lock resources
- views collection for storing read-only views
- search collection for searching form instance data
- schemas collection for XML Schemas
- Create Application Template Files
- edit.xq - XForms editor for new records and updating records (generated form the XML Schema)
- new-instance.xml - default data for a new record
- search-fomn.xq - Generates an XForms application for searching
- search.xq - XQuery for searching records - return an HTML results page
- list-items.xq - A one-line summary of each XForms instance
- view-item.xq - A one-line summary of each XForms instance
As you can see the actions are the creation of server-side collections and files that are parameterized by the form instance.
Similarities to Ant Build Scripts
[edit | edit source]The application builder server-side script is similar to Apache build scripts in several ways. With Ant a series of folders and files are created when a build script is executed.
Screen Image
[edit | edit source]
Discussion
[edit | edit source]
Dashboard Builder
Motivation
[edit | edit source]You want a single form that allows you to layout a single page dashboard. In this case a dashboard in a set of "Portlets" that each have separate content.
Method
[edit | edit source]Our dashboard builder will control a library of dashboards. Each dashboard has a name, layout information and a list of portlets that are rendered in the dashboard. In our example a dashboard may have up to 36 portlets, but best practices usually contain 7 portlets plus or minus one or two.
Application Design
[edit | edit source]Our dashboard layout will be one of three types:
- row oriented where all portlets in a row have the same height
- column oriented where all portlets in a column share the same width
- grid-oriented where all portlets must be contained in a regular grid structure
The tool will allow the user to create a new dashboard and give it a name. The user then selects one of the three layout types. Each layout type will allows the user to specify attributes of each row or column such as using absolute width/heights in pixels or relative height/width percentage of width/heights. Note that to allow dashboards to be resized to different screen sizes, relative sizes should be used.
Within each row, column or grid, the user can specify a set of portlets and then give each portlet some parameters.
When the user saves a dashboard it will save an XML instance document with the specification of the dashboard layout. This layout can be transformed using XQuery or XSLT into a CSS file that is loaded each time the dashboard is displayed.
Dashboard Layout Styles
[edit | edit source]-
Row
-
Column
-
Grid
Conditional Display of Row/Column Information
[edit | edit source]This form should only display the row height specification if either row or grid layout is chosen. Similarly, the column widths should only be displayed if either the column or grid layout is chosen.
The following code provides this logic.
<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>Demonstration of relevant fields.</title>
<xf:model>
<xf:instance id="my-data" xmlns="">
<data>
<DashboardLayoutCode>row</DashboardLayoutCode>
</data>
</xf:instance>
<xf:instance id="views" xmlns="">
<data>
<row-info />
<col-info />
</data>
</xf:instance>
<xf:bind nodeset="instance('views')/row-info" relevant="instance('my-data')/DashboardLayoutCode!='col' " />
<xf:bind nodeset="instance('views')/col-info" relevant="instance('my-data')/DashboardLayoutCode!='row'" />
</xf:model>
<body>
<p>Demonstration of relevant fields. Grid layouts require both rows and columns to be specified.</p>
<xf:select1 ref="instance('my-data')/DashboardLayoutCode">
<xf:label>Enter Layout Type: </xf:label>
<xf:item>
<xf:label>Row</xf:label>
<xf:value>row</xf:value>
</xf:item>
<xf:item>
<xf:label>Col</xf:label>
<xf:value>col</xf:value>
</xf:item>
<xf:item>
<xf:label>Grid</xf:label>
<xf:value>grid</xf:value>
</xf:item>
</xf:select1>
<br />
<xf:group ref="instance('views')/row-info">
<h1>Row</h1>
</xf:group>
<xf:group ref="instance('views')/col-info">
<h1>Col</h1>
</xf:group>
</body>
</html>
Source Code
[edit | edit source]NOTE: In development!
<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 Title</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Helvetica, sans-serif;}
/* 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 170px 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, xf|output > xf|label
{text-align:right; padding-right:10px; width:170px; float:left; text-align:right; font-weight: bold;}
.DashboardDescriptionText textarea {
width: 400px;
height: 8em;
font-family:Helvetica, sans-serif;
}
/* anything marked as a cell is inside a table */
.cell * {display: inline; padding: 1px 1px;}
/* set to column widths in the portlet table */
.PortletID {width: 10px;}
.PortletRow {width: 10px;}
.RowPlacement {width: 10px;}
.PortletHeight {width: 10px;}
.PortletWidth {width: 10px;}
</style>
<xf:model>
<xf:instance id="my-dash" xmlns="">
<DashboardDocument>
<DashboardID>123</DashboardID>
<DashboardName>Sample Dashboard</DashboardName>
<DashboardDescriptionText>A full description of the </DashboardDescriptionText>
<DashboardKeywords>test, example, sample</DashboardKeywords>
<DashboardLayoutCode>row</DashboardLayoutCode>
<DashboardRowCount>3</DashboardRowCount>
<DashboardColumnCount>4</DashboardColumnCount>
<Rows>
<Row>
<RowHeight>20%</RowHeight>
</Row>
<Row>
<RowHeight>50%</RowHeight>
</Row>
<Row>
<RowHeight>30%</RowHeight>
</Row>
</Rows>
<Portlets>
<Portlet>
<PortletID>1</PortletID>
<PortletName>Portlet1</PortletName>
<RowPlacement>1</RowPlacement>
<PortletWidth>25%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>2</PortletID>
<PortletName>Portlet2</PortletName>
<RowPlacement>1</RowPlacement>
<PortletWidth>25%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>3</PortletID>
<PortletName>Portlet3</PortletName>
<RowPlacement>1</RowPlacement>
<PortletWidth>25%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>4</PortletID>
<PortletName>Portlet4</PortletName>
<RowPlacement>1</RowPlacement>
<PortletWidth>25%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>5</PortletID>
<PortletName>Portlet5</PortletName>
<RowPlacement>2</RowPlacement>
<PortletWidth>33%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>6</PortletID>
<PortletName>Portlet3</PortletName>
<RowPlacement>2</RowPlacement>
<PortletWidth>33%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>7</PortletID>
<PortletName>Portlet3</PortletName>
<RowPlacement>2</RowPlacement>
<PortletWidth>33%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>8</PortletID>
<PortletName>Portlet3</PortletName>
<RowPlacement>3</RowPlacement>
<PortletWidth>33%</PortletWidth>
<PortletHeight />
</Portlet>
<Portlet>
<PortletID>9</PortletID>
<PortletName>Portlet3</PortletName>
<RowPlacement>3</RowPlacement>
<PortletWidth>33%</PortletWidth>
<PortletHeight />
</Portlet>
</Portlets>
</DashboardDocument>
</xf:instance>
<!-- used to select the number of rows and columns -->
<xf:instance id="layout-items" xmlns="">
<data>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
</data>
</xf:instance>
<!-- named views that are conditionally relevent based on the rules -->
<xf:instance id="views" xmlns="">
<data>
<row-view />
<col-view />
</data>
</xf:instance>
<!-- the rules on how to display the views -->
<!-- if we have a row or grid oriented display get the number of rows -->
<xf:bind id="row-view" nodeset="instance('views')/row-view" relevant="instance('my-dash')/DashboardLayoutCode='row' | instance('my-dash')/DashboardLayoutCode='grid'" />
<!-- if we have a column or grid oriented display get the number of columns -->
<xf:bind id="col-view" nodeset="instance('views')/col-view" relevant="instance('my-dash')/DashboardLayoutCode='col' | instance('my-dash')/DashboardLayoutCode='grid'" />
</xf:model>
</head>
<body>
<xf:output ref="DashboardID">
<xf:label>Dashboard ID:</xf:label>
</xf:output>
<xf:input ref="DashboardName">
<xf:label>Dashboard Name</xf:label>
<xf:hint>A short name under 50 characters.</xf:hint>
</xf:input>
<xf:textarea ref="DashboardDescriptionText" class="DashboardDescriptionText">
<xf:label>Description:</xf:label>
<xf:hint>Full description text. Used for searching for dashboards.</xf:hint>
</xf:textarea>
<xf:input ref="DashboardKeywords">
<xf:label>Keywords:</xf:label>
<xf:hint>Use comma to separate keywords.</xf:hint>
</xf:input>
<xf:select1 ref="DashboardLayoutCode">
<xf:label>Layout Style:</xf:label>
<xf:item>
<xf:label>Row</xf:label>
<xf:value>row</xf:value>
</xf:item>
<xf:item>
<xf:label>Column</xf:label>
<xf:value>col</xf:value>
</xf:item>
<xf:item>
<xf:label>Grid</xf:label>
<xf:value>grid</xf:value>
</xf:item>
</xf:select1>
<xf:group ref="instance('views')/row-view">
<xf:group ref="instance('my-dash')">
<xf:select1 ref="DashboardRowCount">
<xf:label>Number of Rows: </xf:label>
<xf:itemset nodeset="instance('layout-items')/item">
<xf:item>
<xf:label ref="." />
<xf:value ref="." />
</xf:item>
</xf:itemset>
</xf:select1>
</xf:group>
</xf:group>
<xf:group ref="instance('views')/col-view">
<xf:group ref="instance('my-dash')">
<xf:select1 ref="DashboardColumnCount">
<xf:label>Number of Columns: </xf:label>
<xf:itemset nodeset="instance('layout-items')/item">
<xf:item>
<xf:label ref="." />
<xf:value ref="." />
</xf:item>
</xf:itemset>
</xf:select1>
</xf:group>
</xf:group>
<table>
<thead>
<tr>
<th class="cell PortletID">ID</th>
<th class="cell PortletName">Name</th>
<th class="cell RowPlacement">Placement</th>
<th class="cell PortletHeight">Height</th>
<th class="cell PortletWidth">Width</th>
</tr>
</thead>
</table>
<xf:repeat nodeset="instance('my-dash')/Portlets/Portlet">
<span class="cell PortletID">
<xf:input ref="PortletID"/>
</span>
<span class="cell PortletName">
<xf:input ref="PortletName"/>
</span>
<span class="cell RowPlacement">
<xf:input ref="RowPlacement"/>
</span>
<span class="cell PortletHeight">
<xf:input ref="PortletHeight"/>
</span>
<span class="cell PortletWidth">
<xf:input ref="PortletWidth"/>
</span>
</xf:repeat>
</body>
</html>
References
[edit | edit source]Dashboards are common features in web portals. For interoperability, the content of each portlet can be specified by CSS tags specified in the JSR-168 specification. JSR-168 is also designed to be consistent with the OASIS Web Services for Remote Portlets standard.
For an excellent guild to the human-factors best-practices creating portlets see Stephen Few's excellent book Information Dashboard Design. For an excellent reference on what measures to use see Performance Dashboards by Wayne W. Erickson Portal standards are also discussed in the book Portal Development with Open Source Tools by Richardson et. el.
URL Rewriter
Motivation
[edit | edit source]You want a nice easy-to-use form to configure and test URL rewriting rules that can be use with the Jetty web server.
Here is the overall structure of the Jetty configuration file:
<Configure id="Server" class="org.mortbay.jetty.Server">
<Get id="oldhandler" name="handler"/>
<Set name="handler">
<New id="Rewrite" class="org.mortbay.jetty.handler.rewrite.RewriteHandler">
...
<!-- redirect an entire directory of content -->
<Call name="addRewriteRule">
<Arg>/db/app/data/path/to/old/file.xml</Arg>
<Arg>/newfile.xml</Arg>
</Call>
<!-- redirect an entire directory of content -->
<Call name="addRewriteRule">
<Arg>/some/old/context/*</Arg>
<Arg>/test/dump/newcontext</Arg>
</Call>
<!-- add a regex rule -->
<Call name="addRule">
<Arg>
<New class="org.mortbay.jetty.handler.rewrite.RewriteRegexRule">
<Set name="regex">/test/dump/regex/([^/]*)/(.*)</Set>
<Set name="replacement">/test/dump/$2/$1</Set>
</New>
</Arg>
</Call>
</New>
</Set>
</Configure>
You will note that there are two blocks of repeating elements. One for addRule and one for addRewriteRule. Our XForms application with have two repeating structures, one for each of these rules.
Structure of the form
[edit | edit source]Our form will have a single line for each rewrite rule. When you click on that rule it will display an inspector below that has a type-sensitive editor for that rule. Under the rule there will be a button to test the rule by sending the rule to a regex test server. This will run the rule on the input test cases and return the results.
Discussion
[edit | edit source]
Web Service Tester
Motivation
[edit | edit source]You want a generic tool for testing a REST web service. You want to be able to put in a URI and an instance document and see what data is returned.
Screen Images
[edit | edit source]Source Code
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>REST Service Tester</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family: Ariel,Helvetica,sans-serif;}
.header {font-weight: bold;}
xf|group {border: black solid 1px; padding:10px; margin: 15px 5px;}
.group-label {display:block; position:relative; font-weight:bold;font-size:12pt;
background-color: silver; margin: 3px; width: 30%;
padding: 2px 4px; top: -20px; left: -3px;}
.url .xf-value {width: 100%;}
</style>
<xf:model>
<xf:instance id="atomFeed">
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Atom Feed</title>
</feed>
</xf:instance>
<xf:instance id="resource">
<root xmlns="">
<resource>http://xformstest.org/cgi-bin/echo.sh</resource>
</root>
</xf:instance>
<xf:instance xmlns="" id="messages">
<messages>
<xforms-submit-error>
<error-type/>
<resource-uri/>
<response-status-code/>
<response-headers/>
<response-reason-phrase/>
<response-body/>
</xforms-submit-error>
<xforms-submit-done>
<resource-uri/>
<response-status-code/>
<response-headers/>
<response-reason-phrase/>
</xforms-submit-done>
</messages>
</xf:instance>
<xf:submission id="submit" replace="none" ref="instance('atomFeed')" method="post"
mediatype="application/atom+xml">
<xf:resource value="instance('resource')/resource"/>
<xf:action ev:event="xforms-submit-error">
<xf:setvalue ref="instance('messages')/xforms-submit-error/error-type"
value="event('error-type')"/>
<xf:setvalue ref="instance('messages')/xforms-submit-error/resource-uri"
value="event('resource-uri')"/>
<xf:setvalue ref="instance('messages')/xforms-submit-error/response-status-code"
value="event('response-status-code')"/>
<xf:setvalue ref="instance('messages')/xforms-submit-error/response-headers"
value="event('response-headers')"/>
<xf:setvalue
ref="instance('messages')/xforms-submit-error/response-reason-phrase"
value="event('response-reason-phrase')"/>
<xf:setvalue ref="instance('messages')/xforms-submit-error/response-body"
value="event('response-body')"/>
</xf:action>
<xf:action ev:event="xforms-submit-done">
<xf:setvalue ref="instance('messages')/xforms-submit-done/resource-uri"
value="event('resource-uri')"/>
<xf:setvalue ref="instance('messages')/xforms-submit-done/response-status-code"
value="event('response-status-code')"/>
<xf:insert nodeset="instance('messages')/xforms-submit-done/response-headers"
origin="event('response-headers')"/>
<xf:setvalue
ref="instance('messages')/xforms-submit-done/response-reason-phrase"
value="event('response-reason-phrase')"/>
</xf:action>
</xf:submission>
</xf:model>
</head>
<body>
<div class="header">XForms Service Tester</div>
<!-- Form for entering the resource URI -->
<xf:group ref="instance('resource')">
<xf:label class="group-label">Submission Data</xf:label>
<span class="prompt-nl">Enter the web address (URL) to which you would like to submit the instance:</span>
<xf:input ref="resource" class="url"/>
</xf:group>
<!-- Submit Response Messages -->
<xf:group ref="instance('messages')/xforms-submit-error">
<xf:label class="group-label">Error Messages</xf:label>
<xf:output ref="error-type">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<xf:output ref="resource-uri">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<xf:output ref="response-status-code">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<xf:output ref="response-headers">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<xf:output ref="response-reason-phrase">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<xf:output ref="response-body">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
</xf:group>
<xf:group ref="instance('messages')/xforms-submit-done">
<xf:label class="group-label">Submit Done Messages</xf:label>
<xf:output ref="resource-uri">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<br/>
<xf:output ref="response-status-code">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
<xf:group ref="response-headers">
<xf:label class="group-label">
<xf:output value="name(.)"/>
</xf:label>
<xf:repeat nodeset="../header">
<xf:output ref="./value">
<xf:label><xf:output ref="../name"/>: </xf:label>
</xf:output>
</xf:repeat>
</xf:group>
<xf:output ref="response-reason-phrase">
<xf:label>
<xf:output value="name(.)"/>
</xf:label>
</xf:output>
</xf:group>
<!-- Submission Button -->
<xf:submit ev:event="DOMActivate" submission="submit">
<xf:label>Submit</xf:label>
</xf:submit>
</body>
</html>
Discussion
[edit | edit source]The response area could be hidden in a switch/case view and a toggle done after submission.
Acknowledgments
[edit | edit source]Thanks to Fraser for this suggestion.
Synonym Set Editor
Motivation
[edit | edit source]You want to associate a synonym set with a single business term. A synonym set is a group of terms that have similar meaning or similar semantics. They are grouped together in a structure called a synonyms set. A term can be associated with one-and-only-one synonym set.
These tools are frequently used during the process of creating an enterprise-wide controlled vocabulary. These vocabularies are used for identifying data elements or expressing business rules in a consistent way across multiple organizations.
Method
[edit | edit source]In this program we will have once instance that has an initial synonym set. We will have a button that reveals alternative synonyms using a switch/case. When you select a new synonym set it will copy the selected synonym set tree into the selected synonym set and close the case.
Sample Program Code
[edit | edit source]<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:ev="http://www.w3.org/2001/xml-events" >
<head>
<title>Test of XForm to Associate Synonym Set to Business Term</title>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Helvetica, sans-serif}
.preferred {font-weight:bold;}
.synonym xf|repeat * {display:inline}
.url {color: blue; text-decoration:underline; margin: 0 2px;}
.syn-list {background-color: sliver;}
</style>
<xf:model>
<xf:instance xmlns="" id="current-synset">
<SynSet>
<synset-id>2</synset-id>
<synonym>
<preferred>false</preferred>
<syn-name>Middle Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Central Item</syn-name>
</synonym>
<synonym>
<preferred>true</preferred>
<syn-name>Second Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Following Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>After First Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Following Item</syn-name>
</synonym>
</SynSet>
</xf:instance>
<xf:instance xmlns="" id="synonym-sets">
<SynSets>
<SynSet>
<synset-id>1</synset-id>
<synonym>
<preferred>false</preferred>
<syn-name>Origin Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>First Item</syn-name>
</synonym>
<synonym>
<preferred>true</preferred>
<syn-name>Initial Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Stat Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Begin Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Originating Item</syn-name>
</synonym>
</SynSet>
<SynSet>
<synset-id>2</synset-id>
<synonym>
<preferred>false</preferred>
<syn-name>Middle Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Central Item</syn-name>
</synonym>
<synonym>
<preferred>true</preferred>
<syn-name>Second Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Following Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>After First Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Following Item</syn-name>
</synonym>
</SynSet>
<SynSet>
<synset-id>3</synset-id>
<synonym>
<preferred>false</preferred>
<syn-name>Final Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Ending Item</syn-name>
</synonym>
<synonym>
<preferred>true</preferred>
<syn-name>Last Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>End Item</syn-name>
</synonym>
<synonym>
<preferred>false</preferred>
<syn-name>Tail Item</syn-name>
</synonym>
</SynSet>
</SynSets>
</xf:instance>
<!-- the URL that the user selected and is executed in the load -->
<xf:instance xmlns="" id="URL-container">
<URL/>
</xf:instance>
</xf:model>
</head>
<body>
<h3>Test of XForm to Associate Synonym Set to Term</h3>
<xf:group class="synonym">
<xf:label class="group-label">Synonyms for This Term:</xf:label>
<xf:repeat nodeset="instance('current-synset')/synonym" id="synonym-repeat">
<xf:trigger appearance="minimal" class="url">
<xf:label>
<xf:group ref=".[preferred='true']">
<xf:output ref="syn-name" class="preferred"/>
</xf:group>
<xf:group ref=".[preferred='false']">
<xf:output ref="syn-name"/>
</xf:group>
</xf:label>
<xf:hint>
<xf:output ref="syn-name"/>
</xf:hint>
<!-- we build a URI and load it if the user clicks on a link -->
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('URL-container')" value="concat('http://www.example.com/view-term.xq?name=', instance('current-synset')/synonym[index('synonym-repeat')=position()]/syn-name)"/>
<xf:load ref="instance('URL-container')"/>
</xf:action>
</xf:trigger>
</xf:repeat>
<xf:switch>
<xf:case id="init">
<xf:trigger>
<xf:label>Change Synonym Set</xf:label>
<xf:toggle case="list-synsets" ev:event="DOMActivate"/>
</xf:trigger>
</xf:case>
<xf:case id="list-synsets">
<h3>Set New Synonym Set:</h3>
<xf:repeat nodeset="instance('synonym-sets')/SynSet" id="set-repeat">
<xf:trigger>
<xf:label>Set</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="instance('current-synset')"
origin="instance('synonym-sets')/SynSet[index('set-repeat')]" />
<xf:toggle case="init" />
</xf:action>
</xf:trigger>
<xf:repeat nodeset="synonym">
<xf:trigger appearance="minimal" class="url">
<xf:label>
<xf:group ref=".[preferred='true']">
<xf:output ref="syn-name" class="preferred"/>
</xf:group>
<xf:group ref=".[preferred='false']">
<xf:output ref="syn-name"/>
</xf:group>
</xf:label>
<!-- we build a URI and load it if the user clicks on a link -->
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('URL-container')"
value="concat('http://www.example.com/view-term.xq?name=', instance('current-synset')/synonym[index('synonym-repeat')=position()]/syn-name)"/>
<xf:load ref="instance('URL-container')"/>
</xf:action>
</xf:trigger>
</xf:repeat>
<br/>
</xf:repeat>
<xf:trigger>
<xf:label>Close Synonym Sets List</xf:label>
<xf:toggle case="init" ev:event="DOMActivate"/>
</xf:trigger>
</xf:case>
</xf:switch>
</xf:group>
</body>
</html>
Discussion
[edit | edit source]
Complex/W2
This example is based on the example on the Mozilla web site:
Notes
[edit | edit source]- Requires javascript
- This uses the switch and case commands
- This uses a CSS style sheet
- This also integrates a simple SVG example
Invoice Manager
Motivation
[edit | edit source]You want to demonstrate a typical business application such as the creation of an Invoice. The invoice must have date and Boolean data types and use a bind rule to automatically calculate invoice totals. The invoice should have multiple line items, each with an amount.
Method
[edit | edit source]We will use many of the standard XForms controls and a standard XForms style sheet to style the form.
Screen Image
[edit | edit source]Sample Application
[edit | edit source]Load Sample XForms Application
Sample Invoice Instance
[edit | edit source]The following is a sample of an invoice document. This document is typically sent by a supplier to a consumer of a product or service after confirmation that the products or services were delivered.
The top portion has items such as an invoice number, the date the invoice was sent to the customer and the from and to information. It is then followed by a set of line items that specify the items delivered and their price. At the end the line items are totaled and an indication made to see if the invoice was paid or not.
<Invoice>
<InvoiceID>123</InvoiceID>
<InvoiceDate>2008-10-10</InvoiceDate>
<From>
<OrganizationName>Acme Services</OrganizationName>
<OrganizationAddress>123 Main St.
Anytown, MN 12345</OrganizationAddress>
</From>
<To>
<OrganizationName>Acme Consumer</OrganizationName>
<OrganizationAddress>123 Main St.
Anytown, MN 12345</OrganizationAddress>
</To>
<LineItems>
<Item>
<Description>Widget 123</Description>
<Amount>100.00</Amount>
</Item>
<Item>
<Description>Widget 456</Description>
<Amount>200.00</Amount>
</Item>
<Item>
<Description>Widget 789</Description>
<Amount>300.00</Amount>
</Item>
</LineItems>
<TotalAmount></TotalAmount>
<InvoiceTermsCode>net-30</InvoiceTermsCode>
<PaidIndicator>false</PaidIndicator>
</Invoice>
XForms User Interface
[edit | edit source]The interface to the Invoice uses input, textarea and select1 controls. In addition, data types are assigned to the InvoiceDate and InvoicePaid indicator elements.
XForms Application Source
[edit | edit source]<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>Invoice</title>
<link rel="stylesheet" type="text/css" href="xforms.css"/>
<xf:model>
<xf:instance xmlns="" id="invoice" src="new-instance.xml"/>
<xf:bind nodeset="instance('invoice')/InvoiceDate" type="xs:date"/>
<xf:bind nodeset="instance('invoice')/PaidIndicator" type="xs:boolean"/>
<xf:bind id="total" nodeset="instance('invoice')/TotalAmount" calculate="sum(instance('invoice')/LineItems/Item/Amount)"/>
</xf:model>
</head>
<body>
<h1>Invoice</h1>
<xf:input ref="InvoiceID" class="newline">
<xf:label>Invoice Number: </xf:label>
</xf:input>
<xf:input ref="InvoiceDate" class="newline">
<xf:label>Invoice Date: </xf:label>
</xf:input>
<xf:group ref="instance('invoice')/From">
<xf:label class="group-label">From: </xf:label>
<xf:input ref="OrganizationName" class="newline">
<xf:label>Company: </xf:label>
</xf:input>
<xf:textarea ref="OrganizationAddress" class="newline">
<xf:label>Address:</xf:label>
</xf:textarea>
</xf:group>
<xf:group ref="instance('invoice')/To">
<xf:label class="group-label">To:</xf:label>
<xf:input ref="OrganizationName" class="newline">
<xf:label>Company: </xf:label>
</xf:input>
<xf:textarea ref="OrganizationAddress" class="newline">
<xf:label>Address:</xf:label>
</xf:textarea>
</xf:group>
<table>
<thead>
<tr>
<th class="Description">Description</th>
<th class="Amount">Amount</th>
</tr>
</thead>
</table>
<xf:repeat nodeset="instance('invoice')/LineItems/Item">
<xf:input ref="Description" class="Description"/>
<xf:input ref="Amount" class="Amount"/>
</xf:repeat>
<xf:input bind="total" class="Amount">
<xf:label>Total: </xf:label>
</xf:input>
<xf:select1 ref="InvoiceTermsCode" class="newline">
<xf:label>Terms: </xf:label>
<xf:item>
<xf:label>Payable on Receipt</xf:label>
<xf:value>payable-on-receipt</xf:value>
</xf:item>
<xf:item>
<xf:label>Net 30</xf:label>
<xf:value>net-30</xf:value>
</xf:item>
<xf:item>
<xf:label>2% discount if paid withn 10 days, Net 30</xf:label>
<xf:value>2-10-net-30</xf:value>
</xf:item>
<xf:item>
<xf:label>Net 60</xf:label>
<xf:value>net-60</xf:value>
</xf:item>
</xf:select1>
<xf:input ref="PaidIndicator" class="newline">
<xf:label>Paid:</xf:label>
</xf:input>
</body>
</html>
Sample CSS File
[edit | edit source]The following CSS file required the input XForms application to add the newline class attribute for each control that appears on a new line. This allows the repeat input items to not automatically flow to a new line.
@namespace xf url("http://www.w3.org/2002/xforms");
body {font-family:Helvetica, sans-serif;}
textarea {font-family:Helvetica, sans-serif;}
.newline {display:block; margin:5px 0;}
xf|input > xf|label, xf|select > xf|label, xf|select1 > xf|label, xf|textarea > xf|label
{text-align:right; padding-right:10px; width:20ex; float:left; text-align:right;}
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;}
/* put each item on a new row */
.xf-repeat-item {padding: 3px; display:block;}
.Description, .Description .xf-value {text-align: left;}
.Description {width: 50ex; text-align: left;}
.Description .xf-value {width: 65ex; text-align: left;}
.Amount, .Amount .xf-value{text-align: right;}
.Amount {width: 12ex;}
.Amount .xf-value {width: 16ex;}
/* add to remove spaces between table cells
table {border-collapse: collapse;} */
thead tr {background-color: silver;}
thead tr th {padding: 2px 5px;}
Discussion
[edit | edit source]
Calculator
One of the classic examples of a web application program is a calculator.
Program
[edit | edit source]<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>
<!-- Licensed by the w3c.org under the GPL2 -->
<title>Calculator Sample</title>
<xf:model>
<xf:instance>
<equation xmlns="">
<display>0</display>
<displaybuffer>0</displaybuffer>
<first>0</first>
<second>0</second>
<memory>0</memory>
<result />
</equation>
</xf:instance>
</xf:model>
<style type="text/css">
table {
border: thin outset;
}
td {
border: thin inset;
}
.display {
text-align: right;
}
</style>
</head>
<body>
<p>A simple calculator</p>
<table>
<tr>
<td colspan="6" class="display">
<xf:output ref="/equation/display" />
</td>
</tr>
<tr>
<td>
<xf:output ref="/equation/memory">
<xf:label>M:</xf:label>
</xf:output>
</td>
<td />
<td />
<td />
<td colspan="2">
<xf:trigger>
<xf:label>Clear</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/first" value="0" />
<xf:setvalue ref="/equation/second" value="0" />
<xf:setvalue ref="/equation/result" value="0" />
<xf:setvalue ref="/equation/display" value="0" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
<xf:toggle case="add" />
</xf:action>
</xf:trigger>
</td>
</tr>
<tr>
<td>
<xf:trigger>
<xf:label>MC</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/memory" value="0" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>7</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 7" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>8</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 8" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>9</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 9" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>/</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/first" value="/equation/display" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
<xf:toggle case="divide" />
</xf:action>
</xf:trigger>
</td>
<td />
</tr>
<tr>
<td>
<xf:trigger>
<xf:label>MR</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/display" value="/equation/memory" />
<xf:setvalue ref="/equation/displaybuffer" value="/equation/memory" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>4</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 4" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>5</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 5" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>6</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 6" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>*</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/first" value="/equation/display" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
<xf:toggle case="multiply" />
</xf:action>
</xf:trigger>
</td>
</tr>
<tr>
<td>
<xf:trigger>
<xf:label>MS</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/memory" value="/equation/display" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>1</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 1" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>2</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 2" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>3</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 3" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>-</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/first" value="/equation/display" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
<xf:toggle case="subtract" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>1/x</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/display" value="1 div /equation/display" />
</xf:action>
</xf:trigger>
</td>
</tr>
<tr>
<td>
<xf:trigger>
<xf:label>M+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/memory" value="/equation/memory + /equation/display" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>0</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10" />
<xf:setvalue ref="/equation/display" value="/equation/displaybuffer" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:trigger>
<xf:label>+/-</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/display" value="/equation/display * -1" />
</xf:action>
</xf:trigger>
</td>
<td />
<td>
<xf:trigger>
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/first" value="/equation/display" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
<xf:toggle case="add" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:switch>
<xf:case id="add" selected="true">
<xf:trigger>
<xf:label>=</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/second" value="/equation/displaybuffer" />
<xf:setvalue ref="/equation/result" value="/equation/first + /equation/second" />
<xf:setvalue ref="/equation/display" value="/equation/result" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
</xf:action>
</xf:trigger>
</xf:case>
<xf:case id="subtract">
<xf:trigger>
<xf:label>=</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/second" value="/equation/displaybuffer" />
<xf:setvalue ref="/equation/result" value="/equation/first - /equation/second" />
<xf:setvalue ref="/equation/display" value="/equation/result" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
</xf:action>
</xf:trigger>
</xf:case>
<xf:case id="multiply">
<xf:trigger>
<xf:label>=</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/second" value="/equation/displaybuffer" />
<xf:setvalue ref="/equation/result" value="/equation/first * /equation/second" />
<xf:setvalue ref="/equation/display" value="/equation/result" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
</xf:action>
</xf:trigger>
</xf:case>
<xf:case id="divide">
<xf:trigger>
<xf:label>=</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="/equation/second" value="/equation/displaybuffer" />
<xf:setvalue ref="/equation/result" value="/equation/first div /equation/second" />
<xf:setvalue ref="/equation/display" value="/equation/result" />
<xf:setvalue ref="/equation/displaybuffer" value="0" />
</xf:action>
</xf:trigger>
</xf:case>
</xf:switch>
</td>
</tr>
</table>
</body>
</html>
Discussion
[edit | edit source]The calculator program is about 300 lines long. But much of the code is just telling what actions should happen when a button gets pressed.
The model of the calculator is very simple. Just a five variables:
- display - the visible display
- displaybuffer - a secondary display that is not visible
- first - the first operator
- second - the second operator
- memory - used by the memory function
Here is the trigger for the "5" button:
<td> <xf:trigger> <xf:label>5</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue ref="/equation/displaybuffer" value="/equation/displaybuffer * 10 + 5" /> <xf:setvalue ref="/equation/display" value="/equation/displaybuffer" /> </xf:action> </xf:trigger> </td>
The actions for the trigger is to do just two things:
- are to multiply the value of the display buffer by 10 (shifting the digits over by one) and then to add a five.
- copy the value of the display buffer to the display.
There are also scientific function calculators but they have a smiliar structure.
It is interesting to compare a JavaScript version to the XForms version. The JavaScript version is shorter but the JavaScript can take advantage of some of the tools that are available to JavaScript.
References
[edit | edit source]
Crime Profile
Crime Incident Example
[edit | edit source]This is a large example posted to the XForms mailing list. It has a number of interesting features.
Source Code
[edit | edit source]<?xml version='1.0' encoding='utf-8'?>
<xhtml:html xmlns:f="http://orbeon.org/oxf/xml/formatting"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fe="http://www.xformsworld.com/bpms/workflow/xforms/TestComplaint/CreateReport"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:stl="http://www.codesynthesis.com/xmlns/xsstl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xhtml:head>
<title>CreateReport</title>
<xhtml:style type="text/css">
@namespace xforms url("http://www.w3.org/2002/xforms");
body { padding-left: 6px; color: black; font-family:
verdana, arial, sans-serif; font-size: 10pt;
background-color: #000099; /*background-image:
url(C:\xformsworld_workspaces_parent_folder
\xformsworld_1067_Stored_Procedure_Works\CriminalComplaint1\images
\blue_preview.jpg);*/
}
.Arrestee_Information,.Vehicle_Information, .Offense_Report{
margin-bottom: 1em }
.Arrestee_Information .all-label,.Offense_Report .all-label
{ display: -moz-inline-box; display: inline-block; width:
expression('9em'); min-width: 9em } .Vehicle_Information
.all-label { display: -moz-inline-box; display:
inline-block; width: expression('9em'); min-width: 9em }
fieldset {width: 700px; margin: 0 auto; padding 10 px 20px;
display:block; clear: left;}
/*table#Offense_Report label { float:left; width:330px;
display: block; margin-right:20px 0; padding-top:0.2em;
text-align:right; font-weight:bold; position: relative; }*/
.Arrestee_Information .form-td,.Vehicle_Information
.form-td, .Offense_Report .form-td { width; 33em;
background: #FFCC99; padding: .5em;
}
.Arrestee_Information .form-td .xforms-input input,
.Vehicle_Information .form-td .xforms-input input,
.Offense_Report .form-td .xforms-input input { /*display:
block; margin-top: 4px; margin-bottom: 4px; margin-left:
20px; width: 400px;*/ width: 20em; margin-bottom: 2px
background-color: rgb(210,230,230); }
/*.xforms-group { background-color:#f2e3c6;
border-style:solid; border-color:#542700; width: 100%;
position: relative; font-family:Georgia, "Times New Roman",
Times, serif; font-size:12px; border: 0.2em solid Navy;
/*margin-left: auto; margin-right: auto;*/ margin:20px 10px
20px 0px; padding: 1em; /*display:table;*/ display:block;
float:left; padding: 0px 10px 10px 10px; }*/
/*.Arrestee_Information .xforms-input input,
.Offense_Information .xforms-input input { /*display: block;
margin-top: 4px; margin-bottom: 4px; margin-left: 20px;*/
width:100%; width: 20em; margin-bottom: 2px margin:2px 0px
0px 0px; background-color:#f2e3c6; padding:1px 2px; display:
table-row; }*/
/* vertical area between input boxes */ input { margin:
.2em; }
/* each label within an input is a cell in the input row */
.xforms-input { font-family: Arial, Helvetica, sans-serif;
font-weight: bold; display: table-cell; width: 150px;
margin: 3px; text-align: right; }
body{ background-color:#bfb39c; }
fieldset.container1{ border: 1px solid #000000; overflow:
auto; width: 100% /*background-color:#f2e3c6;
border-width:10px 0px 0px 0px; border-style:solid;
border-color:#542700;
font-family:Georgia, "Times New Roman", Times, serif;
font-size:12px;
margin:20px 10px 20px 0px; width:100%; position:relative;
float:left; display:table; display:block; padding: 0px 10px
10px 10px;*/ }
</xhtml:style>
<xforms:model schema="CreateReport.xform.xsd">
<!-- This is for address -->
<xs:schema targetNamespace=""
xmlns:stl="http://www.codesynthesis.com/xmlns/xsstl">
<xs:import
namespace="http://www.codesynthesis.com/xmlns/xsstl"
schemaLocation="xsstl.xsd" />
</xs:schema>
<!-- Task Input -->
<xforms:instance id="taskinput">
<fe:input ev:event="DOMActivate">
<fe:name_last />
<fe:name_first />
<fe:name_middle />
<fe:name_suffix />
<fe:address_street_1 />
<fe:address_street_2 />
<fe:address_po_box />
<fe:address_city />
<fe:address_county />
<fe:address_state />
<fe:address_zip />
<fe:address_country />
<fe:incident_date_to />
<fe:incident_date_from />
<fe:officer_name />
<fe:vehicle_VIN />
<fe:vehicle_year />
<fe:vehicle_make />
<fe:vehicle_model />
<fe:vehicle_color />
<fe:vehicle_inspection_sticker />
<fe:vehicle_state_issued />
<fe:vehicle_license_plate />
<fe:incident_time />
<fe:type_complaint />
<fe:arrest_type />
<fe:officer_department />
<fe:id_ccr />
<fe:id_livescan_no />
<fe:Lab_Text>
<fe:Yes_Or_No name="Yes" value="Yes" />
<fe:Yes_Or_No name="No" value="No" />
</fe:Lab_Text>
<fe:incident_location />
<fe:arrest_location />
<fe:arrestee_dob />
<fe:Licensure_State />
<fe:arrest_classification />
<fe:id_ssn />
<fe:phys_desc_race />
<fe:phys_desc_height />
<fe:phys_desc_weight />
<fe:phys_desc_eyes />
<fe:phys_desc_hair />
<fe:phys_desc_build />
<fe:phys_desc_sex />
<fe:id_center />
<fe:id_idnum />
<fe:arrest_time />
<fe:arrest_date />
<fe:take_defendant />
<fe:arrestee_age />
<fe:controls_save />
<fe:super_review_decision />
<fe:Supervisor_Review_Decision_Text />
<fe:SUPERVISOR_REVIEW_Text />
<fe:super_review_comments />
<fe:da_review_decision />
<fe:DA_Decision_Text />
<fe:DA_REVIEW_Text />
<fe:da_review_comments />
<fe:affadavit_accuse_unknown />
<fe:affadavit_narrative />
<fe:I_accuse_John_Doe_Text />
<fe:I_accuse_name_unknown_Text />
<fe:I_accuse_the_above_Text />
<fe:affadavit_accuse_above />
<fe:Spell_Check_Aff_Text />
<fe:AFFADAVIT_NARRATIVE_Text />
<fe:affadavit_date_how_both_know />
<fe:How_both_knows_Text />
<fe:affadavit_how_source_knows />
<fe:How_source_knows_Text />
<fe:affadavit_how_affiant_knows />
<fe:How_Affiant_knows_Text />
<fe:Same_as_Arrest_Date_Text2 />
<fe:affadavit_date_source_received_info />
<fe:Date_source_received_info_Text />
<fe:Same_as_Arrest_Date_Text />
<fe:affadavit_date_affiant_received_info />
<fe:Date_Affiant_received_info_Text />
<fe:WHEN_Text />
<fe:HOW_Text />
<fe:AFFADAVIT_INFORMATION_Text />
<fe:affadavit_other_participants />
<fe:Other_Participants_Do_not_include_above_Defendant />
<fe:affadavit_accuse_doe />
<fe:affadavit_unknown_desc />
<fe:COMPLAINT_INFORMATION_Text />
<fe:Create_Offenses_Text />
<fe:ADDVIEW_ALIASES_Text />
</fe:input>
</xforms:instance>
<!-- Task metadata - used only for People Initiating Processes Task
forms -->
<xforms:instance id="taskmetadata">
<taskmetadata />
</xforms:instance>
<!-- Task Output -->
<xforms:instance id="taskoutput" ev:event="DOMActivate">
<fe:output>
<fe:name_last />
<fe:name_first />
<fe:name_middle />
<fe:name_suffix />
<fe:address_street_1 />
<fe:address_street_2 />
<fe:address_po_box />
<fe:address_city />
<fe:address_county />
<fe:address_state />
<fe:address_zip />
<fe:address_country />
<fe:incident_date_to />
<fe:incident_date_from />
<fe:officer_name />
<fe:vehicle_VIN />
<fe:vehicle_year />
<fe:vehicle_make />
<fe:vehicle_model />
<fe:vehicle_color />
<fe:vehicle_inspection_sticker />
<fe:vehicle_state_issued />
<fe:vehicle_license_plate />
<fe:incident_time />
<COMPLAINT_TYPE
xmlns="http://localhost/simple/xform" Label="Complaint Type" />
<fe:arrest_type />
<fe:officer_department />
<fe:id_ccr />
<fe:id_livescan_no />
<fe:Lab_Text>
<fe:Yes_Or_No name="Yes" value="Yes" />
<fe:Yes_Or_No name="No" value="No" />
</fe:Lab_Text>
<fe:incident_location />
<fe:arrest_location />
<fe:arrestee_dob />
<fe:Licensure_State />
<fe:arrestee_age />
<fe:arrest_classification />
<fe:id_ssn />
<fe:phys_desc_race />
<fe:phys_desc_height />
<fe:phys_desc_weight />
<fe:phys_desc_eyes />
<fe:phys_desc_hair />
<fe:phys_desc_build />
<fe:phys_desc_sex />
<fe:id_center />
<fe:id_idnum />
<fe:arrest_time />
<fe:arrest_date />
<fe:take_defendant />
<fe:controls_save />
<fe:super_review_decision />
<fe:Supervisor_Review_Decision_Text />
<fe:SUPERVISOR_REVIEW_Text />
<fe:super_review_comments />
<fe:da_review_decision />
<fe:DA_Decision_Text />
<fe:DA_REVIEW_Text />
<fe:da_review_comments />
<fe:affadavit_accuse_unknown />
<fe:affadavit_narrative />
<fe:I_accuse_John_Doe_Text />
<fe:I_accuse_name_unknown_Text />
<fe:I_accuse_the_above_Text />
<fe:affadavit_accuse_above />
<fe:Spell_Check_Aff_Text />
<fe:AFFADAVIT_NARRATIVE_Text />
<fe:affadavit_date_how_both_know />
<fe:How_both_knows_Text />
<fe:affadavit_how_source_knows />
<fe:How_source_knows_Text />
<fe:affadavit_how_affiant_knows />
<fe:How_Affiant_knows_Text />
<fe:Same_as_Arrest_Date_Text2 />
<fe:affadavit_date_source_received_info />
<fe:Date_source_received_info_Text />
<fe:Same_as_Arrest_Date_Text />
<fe:affadavit_date_affiant_received_info />
<fe:Date_Affiant_received_info_Text />
<fe:WHEN_Text />
<fe:HOW_Text />
<fe:AFFADAVIT_INFORMATION_Text />
<fe:affadavit_other_participants />
<fe:Other_Participants_Do_not_include_above_Defendant />
<fe:affadavit_accuse_doe />
<fe:affadavit_unknown_desc />
<fe:COMPLAINT_INFORMATION_Text />
<fe:Create_Offenses_Text />
<fe:ADDVIEW_ALIASES_Text />
</fe:output>
</xforms:instance>
<xforms:action ev:event="xforms-ready">
<xforms:action
xforms:if="string(instance('taskoutput')/@saved) != 'true'">
<xforms:setvalue
ref="instance('taskoutput')/fe:name_last"
value="instance('taskinput')/fe:name_last" />
<xforms:setvalue ref="instance('taskoutput')/fe:SSN"
value="instance('taskinput')/fe:SSN" />
<xforms:setvalue
ref="instance('taskoutput')/fe:name_first"
value="instance('taskinput')/fe:name_first" />
<xforms:setvalue
ref="instance('taskoutput')/fe:name_suffix"
value="instance('taskinput')/fe:name_suffix" />
<xforms:setvalue
ref="instance('taskoutput')/fe:name_middle"
value="instance('taskinput')/fe:name_middle" />
<xforms:setvalue
ref="instance('taskoutput')/fe:incident_date_to"
value="instance('taskinput')/fe:incident_date_to" />
<xforms:setvalue
ref="instance('taskoutput')/fe:incident_date_from"
value="instance('taskinput')/fe:incident_date_from" />
<!-- normalize-space function will strip leading and trailing spaces from the value -->
<xforms:setvalue
ref="instance('taskoutput')/fe:address_street_1"
value="normalize-space(instance('taskinput')/fe:address_street_1)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_street_2"
value="normalize-space(instance('taskinput')/fe:address_street_2)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_po_box"
value="normalize-space(instance('taskinput')/
fe:address_po_box)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_city"
value="normalize-space(instance('taskinput')/fe:address_city)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_county"
value="normalize-space(instance('taskinput')" />
fe:address_county)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_state"
value="normalize-space(instance('taskinput')/fe:address_state)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_zip"
value="normalize-space(instance('taskinput')/fe:address_zip)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:address_country"
value="normalize-space(instance('taskinput')" />
fe:address_country)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_VIN"
value="normalize-space(instance('taskinput')/fe:vehicle_VIN)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_make"
value="normalize-space(instance('taskinput')/fe:vehicle_make)"/>
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_year"
value="normalize-space(instance('taskinput')/fe:vehicle_year)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_model"
value="normalize-space(instance('taskinput')/fe:vehicle_model)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_color"
value="normalize-space(instance('taskinput')/fe:vehicle_color)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_inspection_sticker"
value="normalize-space(instance('taskinput')/fe:vehicle_inspection_sticker)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_license_plate"
value="normalize-space(instance('taskinput')/fe:vehicle_license_plate)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:vehicle_state_issued"
value="normalize-space(instance('taskinput')/fe:vehicle_state_issued)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:incident_time"
value="normalize-space(instance('taskinput')/fe:incident_time)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:COMPLAINT_TYPE"
value="normalize-space(instance('taskinput')/fe:COMPLAINT_TYPE)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:arrest_classification"
value="normalize-space(instance('taskinput')/fe:Arrest_Classification)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_race"
value="normalize-space(instance('taskinput')/fe:Race)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:arrest_type"
value="normalize-space(instance('taskinput')/fe:Arrest_Type)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:id_center"
value="normalize-space(instance('taskinput')/fe:id_center)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:officer_department"
value="normalize-space(instance('taskinput')/fe:Department)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:officer_name"
value="normalize-space(instance('taskinput')/fe:officer_name)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:id_ccr"
value="normalize-space(instance('taskinput')/fe:id_ccr)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:id_livescan_no"
value="normalize-space(instance('taskinput')/fe:id_livescan_no)" />
<!--<xforms:setvalue ref="instance('taskoutput')/fe:Lab_Checkbox"
value="normalize-space(instance('taskinput')/fe:Lab_Checkbox)"/>-->
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_height"
value="normalize-space(instance('taskinput')/fe:phys_desc_height)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_weight"
value="normalize-space(instance('taskinput')/fe:phys_desc_weight)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_hair"
value="normalize-space(instance('taskinput')/fe:phys_desc_hair)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_eyes"
value="normalize-space(instance('taskinput')/fe:phys_desc_eyes)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_build"
value="normalize-space(instance('taskinput')/fe:phys_desc_build)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:phys_desc_sex"
value="normalize-space(instance('taskinput')/fe:phys_desc_sex)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:arrest_date"
value="normalize-space(instance('taskinput')/fe:arrest_date)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:arrest_time"
value="normalize-space(instance('taskinput')/fe:arrest_time)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:id_idnum"
value="normalize-space(instance('taskinput')/fe:id_idnum)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:arrestee_dob"
value="normalize-space(instance('taskinput')/fe:arrestee_dob)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:arrestee_age"
value="normalize-space(instance('taskinput')/fe:arrestee_age)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:take_defendant"
value="normalize-space(instance('taskinput')/fe:take_defendant)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Affiant_and__or_other_Police_Officers_Text"
value="instance('taskinput')/fe:Affiant_and__or_other_Police_Officers_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:This_source_made_declaration_Text"
value="instance('taskinput')/fe:This_source_made_declaration_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Source_has_given_information_Text"
value="instance('taskinput')/fe:Source_has_given_information_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Defendants_reputation_Text"
value="instance('taskinput')/fe:Defendants_reputation_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Source_is_presumed_reliable_Text"
value="instance('taskinput')/fe:Source_is_presumed_reliable_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:source_presumed"
value="instance('taskinput')/fe:source_presumed" />
<xforms:setvalue
ref="instance('taskoutput')/fe:source_information"
value="instance('taskinput')/fe:source_information" />
<xforms:setvalue
ref="instance('taskoutput')/fe:defendant_reputation"
value="instance('taskinput')/fe:defendant_reputation" />
<xforms:setvalue
ref="instance('taskoutput')/fe:source_declaration"
value="instance('taskinput')/fe:source_declaration" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affiant_corroborates"
value="instance('taskinput')/fe:affiant_corroborates" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Please_check_all_that_apply_Text"
value="instance('taskinput')/
fe:Please_check_all_that_apply_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:why_affiant_believes_Text"
value="instance('taskinput')/fe:why_affiant_believes_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Refresh_Offenses_Text"
value="instance('taskinput')/fe:Refresh_Offenses_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:controls_save"
value="instance('taskinput')/fe:controls_save" />
<xforms:setvalue
ref="instance('taskoutput')/fe:super_review_decision"
value="instance('taskinput')/fe:super_review_decision" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Supervisor_Review_Decision_Text"
value="instance('taskinput')/
fe:Supervisor_Review_Decision_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:SUPERVISOR_REVIEW_Text"
value="instance('taskinput')/fe:SUPERVISOR_REVIEW_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:super_review_comments"
value="normalize-space(instance('taskinput')/
fe:super_review_comments)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:da_review_decision"
value="instance('taskinput')/fe:da_review_decision" />
<xforms:setvalue
ref="instance('taskoutput')/fe:DA_Decision_Text"
value="instance('taskinput')/fe:DA_Decision_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:DA_REVIEW_Text"
value="instance('taskinput')/fe:DA_REVIEW_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:da_review_comments"
value="normalize-space(instance('taskinput')/
fe:da_review_comments)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:id_otn"
value="instance('taskinput')/fe:id_otn" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_magistrate"
value="instance('taskinput')/fe:affadavit_magistrate" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_accuse_unknown"
value="instance('taskinput')/fe:affadavit_accuse_unknown" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_narrative"
value="normalize-space(instance('taskinput')/
fe:affadavit_narrative)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:I_accuse_John_Doe_Text"
value="instance('taskinput')/fe:I_accuse_John_Doe_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:I_accuse_name_unknown_Text"
value="instance('taskinput')/fe:I_accuse_name_unknown_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:I_accuse_the_above_Text"
value="instance('taskinput')/fe:I_accuse_the_above_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_accuse_above"
value="instance('taskinput')/fe:affadavit_accuse_above" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Spell_Check_Aff_Text"
value="instance('taskinput')/fe:Spell_Check_Aff_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:AFFADAVIT_NARRATIVE_Text"
value="instance('taskinput')/fe:AFFADAVIT_NARRATIVE_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_date_how_both_know"
value="normalize-space(instance('taskinput')/
fe:affadavit_date_how_both_know)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:How_both_knows_Text"
value="instance('taskinput')/fe:How_both_knows_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_how_source_knows"
value="normalize-space(instance('taskinput')/
fe:affadavit_how_source_knows)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:How_source_knows_Text"
value="instance('taskinput')/fe:How_source_knows_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_how_affiant_knows"
value="normalize-space(instance('taskinput')/
fe:affadavit_how_affiant_knows)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:How_Affiant_knows_Text"
value="instance('taskinput')/fe:How_Affiant_knows_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Same_as_Arrest_Date_Text2"
value="instance('taskinput')/fe:Same_as_Arrest_Date_Text2" />
<xforms:setvalue
ref="instance('taskoutput')/
fe:affadavit_date_source_received_info"
value="normalize-space(instance('taskinput')/
fe:affadavit_date_source_received_info)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Date_source_received_info_Text"
value="instance('taskinput')/fe:Date_source_received_info_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Same_as_Arrest_Date_Text"
value="instance('taskinput')/fe:Same_as_Arrest_Date_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_date_affiant_received_info"
value="normalize-space(instance('taskinput')/fe:affadavit_date_affiant_received_info)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Date_Affiant_received_info_Text"
value="instance('taskinput')/fe:Date_Affiant_received_info_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:WHEN_Text"
value="instance('taskinput')/fe:WHEN_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:HOW_Text"
value="instance('taskinput')/fe:HOW_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:AFFADAVIT_INFORMATION_Text"
value="instance('taskinput')/fe:AFFADAVIT_INFORMATION_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_other_participants"
value="normalize-space(instance('taskinput')/
fe:affadavit_other_participants)" />
<xforms:setvalue
ref="instance('taskoutput')/
fe:Other_Participants_Do_not_include_above_Defendant"
value="instance('taskinput')/
fe:Other_Participants_Do_not_include_above_Defendant" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_accuse_doe"
value="instance('taskinput')/fe:affadavit_accuse_doe" />
<xforms:setvalue
ref="instance('taskoutput')/fe:affadavit_unknown_desc"
value="normalize-space(instance('taskinput')/
fe:affadavit_unknown_desc)" />
<xforms:setvalue
ref="instance('taskoutput')/fe:COMPLAINT_INFORMATION_Text"
value="instance('taskinput')/fe:COMPLAINT_INFORMATION_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:Create_Offenses_Text"
value="instance('taskinput')/fe:Create_Offenses_Text" />
<xforms:setvalue
ref="instance('taskoutput')/fe:ADDVIEW_ALIASES_Text"
value="instance('taskinput')/fe:ADDVIEW_ALIASES_Text" />
</xforms:action>
</xforms:action>
<xforms:bind nodeset="instance('taskinput')/fe:name_last"
relevant="true()" required="true" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:name_first"
relevant="true()" required="true" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:name_suffix"
relevant="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:name_middle"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:incident_date_to"
type="xs:date" />
<xforms:bind nodeset="instance('taskinput')/fe:arrestee_dob"
required="true()" type="xs:date" />
<xforms:bind nodeset="instance('taskinput')/fe:arrestee_age"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:address_street_1"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:address_street_2"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:address_po_box"
required="true()"
type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:address_city"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:address_county"
required="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:address_state" required="true()"
type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:address_zip"
required="true()" type="xs:integer" />
<xforms:bind
nodeset="instance('taskinput')/fe:address_country"
required="true()"
type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:vehicle_VIN"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:vehicle_inspection_sticker"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:vehicle_license_plate"
required="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:vehicle_make"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:vehicle_model" required="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:vehicle_color" required="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:vehicle_state_issued"
required="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:vehicle_year"
required="true()" type="xs:gYear" />
<xforms:bind
nodeset="instance('taskinput')/fe:incident_time" required="true()"
type="xs:time" />
<xforms:bind nodeset="instance('taskinput')/fe:officer_name"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:COMPLAINT_TYPE"
required="true()"
type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:arrest_type"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:phys_desc_race"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:arrest_classification"
required="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:id_center"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:officer_department"
required="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:id_ccr"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:id_livescan_no"
required="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:arrest_location"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:phys_desc_height"
type="xs:decimal" />
<xforms:bind
nodeset="instance('taskinput')/fe:phys_desc_weight"
type="xs:float" />
<xforms:bind
nodeset="instance('taskinput')/fe:phys_desc_eyes"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:phys_desc_hair" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:phys_desc_build"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:phys_desc_sex" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:arrest_date"
required="true()" type="xs:date" />
<xforms:bind nodeset="instance('taskinput')/fe:arrest_time"
required="true()" type="xs:time" />
<xforms:bind nodeset="instance('taskinput')/fe:id_idnum"
required="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:take_defendant" relevant="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:take_defendant" relevant="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Affiant_and__or_other_Police_Officers_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Affiant_and__or_other_Police_Officers_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:This_source_made_declaration_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:This_source_made_declaration_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Source_has_given_information_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Source_has_given_information_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Defendants_reputation_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Defendants_reputation_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Source_is_presumed_reliable_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Source_is_presumed_reliable_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:source_presumed"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:source_presumed" relevant="true()"
type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:source_information"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:source_information"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:defendant_reputation"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:defendant_reputation"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:source_declaration"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:source_declaration"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affiant_corroborates"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:affiant_corroborates"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/
fe:Please_check_all_that_apply_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/
fe:Please_check_all_that_apply_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:why_affiant_believes_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:why_affiant_believes_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Refresh_Offenses_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Refresh_Offenses_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:controls_save"
relevant="true()"
type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:controls_save" relevant="true()"
type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:super_review_decision"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:super_review_decision"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/
fe:Supervisor_Review_Decision_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Supervisor_Review_Decision_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:SUPERVISOR_REVIEW_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:SUPERVISOR_REVIEW_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:super_review_comments"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:super_review_comments"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:da_review_decision"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:da_review_decision"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:DA_Decision_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:DA_Decision_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:DA_REVIEW_Text"
relevant="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:DA_REVIEW_Text"
relevant="true()"
type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:da_review_comments"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:da_review_comments"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_accuse_unknown"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_accuse_unknown"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_narrative"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_narrative"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:I_accuse_John_Doe_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:I_accuse_John_Doe_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:I_accuse_name_unknown_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:I_accuse_name_unknown_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:I_accuse_the_above_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:I_accuse_the_above_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_accuse_above"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_accuse_above"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Spell_Check_Aff_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Spell_Check_Aff_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:AFFADAVIT_NARRATIVE_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:AFFADAVIT_NARRATIVE_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_date_how_both_know"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_date_how_both_know"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:How_both_knows_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:How_both_knows_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_how_source_knows"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_how_source_knows"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:How_source_knows_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:How_source_knows_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_how_affiant_knows"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_how_affiant_knows"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:How_Affiant_knows_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:How_Affiant_knows_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Same_as_Arrest_Date_Text2"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Same_as_Arrest_Date_Text2"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/
fe:affadavit_date_source_received_info"
relevant="true()" type="xs:date" />
<xforms:bind
nodeset="instance('taskinput')/
fe:affadavit_date_source_received_info"
relevant="true()" type="xs:date" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Date_source_received_info_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Date_source_received_info_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Same_as_Arrest_Date_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Same_as_Arrest_Date_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/
fe:affadavit_date_affiant_received_info"
relevant="true()" type="xs:date" />
<xforms:bind
nodeset="instance('taskinput')/
fe:affadavit_date_affiant_received_info"
relevant="true()" type="xs:date" />
<xforms:bind
nodeset="instance('taskoutput')/
fe:Date_Affiant_received_info_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Date_Affiant_received_info_Text"
relevant="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskoutput')/fe:WHEN_Text"
relevant="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:WHEN_Text"
relevant="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskoutput')/fe:HOW_Text"
relevant="true()" type="xs:string" />
<xforms:bind nodeset="instance('taskinput')/fe:HOW_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:AFFADAVIT_INFORMATION_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:AFFADAVIT_INFORMATION_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_other_participants"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_other_participants"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/
fe:Other_Participants_Do_not_include_above_Defendant"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/
fe:Other_Participants_Do_not_include_above_Defendant"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_accuse_doe"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_accuse_doe"
relevant="true()" type="xs:anyURI" />
<xforms:bind
nodeset="instance('taskoutput')/fe:affadavit_unknown_desc"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:affadavit_unknown_desc"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:COMPLAINT_INFORMATION_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:COMPLAINT_INFORMATION_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Create_Offenses_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Create_Offenses_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:ADDVIEW_ALIASES_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:ADDVIEW_ALIASES_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskoutput')/fe:Same_as_Above_Location_Text"
relevant="true()" type="xs:string" />
<xforms:bind
nodeset="instance('taskinput')/fe:Same_as_Above_Location_Text"
relevant="true()" type="xs:string" />
<xforms:submission id="debug" xforms:action=""
xforms:method="post" xforms:replace="all" />
</xforms:model>
</xhtml:head>
<xhtml:body>
<!-- Fieldset Here -->
<xhtml:fieldset class="container1">
<xhtml:legend>
<b>Arrestee Information</b>
</xhtml:legend>
<xhtml:table class="Arrestee_Information" width="92%">
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskoutput')/fe:arrest_classification"
selection="closed">
<xforms:label class="all-label">
Arrest Classification
</xforms:label>
<xforms:item>
<xforms:label>
MANSLAUGHTER-NEGLIGENCE
</xforms:label>
<xforms:value>
MANSLAUGHTER-NEGLIGENCE
</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>ROBBERY</xforms:label>
<xforms:value>ROBBERY</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:arrestee_dob"
incremental="true">
<xforms:label class="all-label">
Arrestee Date of Birth:
</xforms:label>
</xforms:input>
<br/>
<xforms:input
ref="instance('taskoutput')/fe:arrestee_age"
incremental="true">
<xforms:label class="all-label">
Arrestee Age:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:name_last">
<xforms:label class="all-label">
Arrestee Last Name:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:name_first">
<xforms:label class="all-label">
Arrestee First Name:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:name_middle">
<xforms:label class="all-label">
Arrestee Middle Name:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:name_suffix">
<xforms:label class="all-label">
Arrestee Suffix:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskoutput')/fe:Licensure_State">
<xforms:label class="all-label">
Licensure State:
</xforms:label>
<xforms:item>
<xforms:label>PA</xforms:label>
<xforms:value>PA</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>MI</xforms:label>
<xforms:value>MI</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>CA</xforms:label>
<xforms:value>CA</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>AZ</xforms:label>
<xforms:value>AZ</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>VA</xforms:label>
<xforms:value>VA</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>SD</xforms:label>
<xforms:value>SD</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>TN</xforms:label>
<xforms:value>TN</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>UT</xforms:label>
<xforms:value>VT</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>PA</xforms:label>
<xforms:value>PA</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>WA</xforms:label>
<xforms:value>WA</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>WV</xforms:label>
<xforms:value>WV</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>WI</xforms:label>
<xforms:value>WI</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>WY</xforms:label>
<xforms:value>WY</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>SC</xforms:label>
<xforms:value>SC</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>RI</xforms:label>
<xforms:value>RI</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>OR</xforms:label>
<xforms:value>OR</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskoutput')/fe:phys_desc_race">
<xforms:label class="all-label">
Race:
</xforms:label>
<xforms:item>
<xforms:label>Asian</xforms:label>
<xforms:value>Asian</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Hispanic</xforms:label>
<xforms:value>Hispanic</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:phys_desc_height">
<xforms:label class="all-label">
Height
</xforms:label>
<xforms:hint class="all-hint">
Enter Arrestee height in feet and inches
</xforms:hint>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:phys_desc_weight">
<xforms:label class="all-label">
Weight
</xforms:label>
<xforms:hint class="all-hint">
Enter Arrestee Weight in pounds
</xforms:hint>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td" width="30%">
<xforms:select1
ref="instance('taskoutput')/fe:phys_desc_eyes">
<xforms:label class="all-label">
Eyes:
</xforms:label>
<xforms:item>
<xforms:label>Black</xforms:label>
<xforms:value>Black</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Blue</xforms:label>
<xforms:value>Blue</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Grey</xforms:label>
<xforms:value>Grey</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Brown</xforms:label>
<xforms:value>Brown</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Green</xforms:label>
<xforms:value>Green</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Grey</xforms:label>
<xforms:value>Grey</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Hazel</xforms:label>
<xforms:value>Hazel</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Amber</xforms:label>
<xforms:value>Amber</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>
Violet and Red
</xforms:label>
<xforms:value>
Violet and Red
</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
<xhtml:td class="form-td" width="30%">
<xforms:select1
ref="instance('taskoutput')/fe:phys_desc_sex">
<xforms:label class="all-label">
Sex:
</xforms:label>
<xforms:item>
<xforms:label>Male</xforms:label>
<xforms:value>Male</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Female</xforms:label>
<xforms:value>Female</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskoutput')/fe:phys_desc_hair">
<xforms:label class="all-label">
Hair Color:
</xforms:label>
<xforms:item>
<xforms:label>Blonde</xforms:label>
<xforms:value>Blonde</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Brown</xforms:label>
<xforms:value>Brown</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Black</xforms:label>
<xforms:value>Black</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Red</xforms:label>
<xforms:value>Red</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Grey</xforms:label>
<xforms:value>Grey</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:phys_desc_build">
<xforms:label>Build:</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_street_1"
incremental="true">
<xforms:label class="all-label">
Street Address 1:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_street_2"
incremental="true">
<xforms:label class="all-label">
Street Address 2:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_po_box"
incremental="true">
<xforms:label class="all-label">
PO Box:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_city" incremental="true">
<xforms:label class="all-label">
City:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_county"
incremental="true">
<xforms:label class="all-label">
County:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_state"
incremental="true">
<xforms:label class="all-label">
State:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:address_zip" incremental="true">
<xforms:label class="all-label">
Zip:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:address_country">
<xforms:label>Country:</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
</xhtml:table>
</xhtml:fieldset>
<!-- Offence Report Section here -->
<!--<xforms:group appearance="xxforms:group">-->
<!--<xhtml:fieldset style="background-color:#cccc99;
position:relative; left:2ex; top:2ex; width:1500px;
padding:3ex; border-width:1px; border-color:#000033; font-size:
85%">-->
<xhtml:fieldset class="container1">
<LEGEND>
<b>Offence Report</b>
</LEGEND>
<xhtml:table class="Offense_Report" width="92%">
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskinput')/fe:arrest_type" selection="closed">
<xforms:label class="all-label">Arrest Type:</xforms:label>
<xforms:item>
<xforms:label>Arrests</xforms:label>
<xforms:value>Arrests</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Warrants</xforms:label>
<xforms:value>Warrants</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Summons</xforms:label>
<xforms:value>Summons</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskinput')/fe:officer_department"
selection="closed">
<xforms:label class="all-label">Department:</xforms:label>
<xforms:item>
<xforms:label>
Department 1
</xforms:label>
<xforms:value>
Department 1
</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>
Department 2
</xforms:label>
<xforms:value>
Department 2
</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:officer_name">
<xforms:label class="all-label">
Officer Name:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td>
<xforms:input
ref="instance('taskinput')/fe:id_ccr" name="id_ccr"
id="id_ccr">
<xforms:label class="all-label">
CCR Number:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:incident_date_from"
incremental="true">
<xforms:label class="all-label">
Incident Date From:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:incident_date_to"
incremental="true">
<xforms:label class="all-label">
Incident Date To:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:incident_time"
incremental="true">
<xforms:label class="all-label">
Incident Time:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:select
ref="instance('taskinput')/fe:Lab_Text" appearance="full">
<xforms:label class="all-label">
Criminal Lab Services Requested?
</xforms:label>
<xforms:itemset
nodeset="instance('taskoutput')/fe:Lab_Text/fe:Yes_Or_No">
<xforms:label ref="@name" />
<xforms:value ref="@value" />
</xforms:itemset>
</xforms:select>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:select1
ref="instance('taskinput')/fe:id_center" selection="closed">
<xforms:label class="all-label">
ID Center:
</xforms:label>
<xforms:item>
<xforms:label>
ID Center 1
</xforms:label>
<xforms:value>
ID Center 1
</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>
ID Center 2
</xforms:label>
<xforms:value>
ID Center 2
</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:id_livescan_no"
incremental="true">
<xforms:label class="all-label">
LiveScan No:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:arrest_date"
incremental="true">
<xforms:label class="all-label">
Arrest Date:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:arrest_time"
incremental="true">
<xforms:label class="all-label">
Arrest Time:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td" colspan="2">
<xforms:input
ref="instance('taskinput')/fe:id_idnum" incremental="true">
<xforms:label class="all-label">
Dept.Incident No:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td" colspan="2">
<xforms:textarea
class="Crim_Inc_Loc_Textarea"
ref="instance('taskinput')/fe:incident_location"
appearance="xxforms:autosize" incremental="true">
<xforms:label class="all-label">
Criminal Incident Location:
</xforms:label>
</xforms:textarea>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td" colspan="2">
<xforms:textarea class="Arrest_Loc_Textarea"
ref="instance('taskinput')/fe:arrest_location"
appearance="xxforms:autosize" incremental="true">
<xforms:label class="all-label">
Arrest Location:
</xforms:label>
</xforms:textarea>
<xforms:trigger>
<xforms:label class="all-label">
Same as Above
</xforms:label>
<xforms:action ev:event="DOMActivate">
<!--<xforms:insert nodeset="instance('taskinput')/
fe:Crim_Inc_Loc_Textarea" at="index('Crim_Inc_Loc_Textarea')"
position="before" />-->
<!-- Could I not have used xforms:insert? if not, why? -->
<!--<xforms:setvalue ref="instance('taskinput')/
fe:Arrest_Loc_Textarea[index('Arrest_Loc_Textarea')]"
value="instance('taskinput')/fe:Crim_Inc_Loc_Textarea" />-->
<!--The right syntax <xforms:setvalue ev:event="DOMActivate"
ref="/data/destination" value="/data/source" /> -->
<!-- Why did it work when I removed the index[] construct
alone -->
<xforms:setvalue
ref="instance('taskinput')/fe:arrest_location"
value="instance('taskinput')/fe:incident_location" />
</xforms:action>
</xforms:trigger>
</xhtml:td>
</xhtml:tr>
</xhtml:tr>
</xhtml:table>
</xhtml:fieldset>
<!-- Vehicle information -->
<xhtml:fieldset class="container1">
<xhtml:table class="Vehicle_Information" width="92%">
<xhtml:legend>
<b>Vehicle Information</b>
</xhtml:legend>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskoutput')/fe:vehicle_VIN" incremental="true">
<xforms:label class="all-label">
VIN:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_year" incremental="true">
<xforms:label class="all-label">
Year:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_make" incremental="true">
<xforms:label class="all-label">
Make:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_model"
incremental="true">
<xforms:label class="all-label">
Model:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_color"
incremental="true">
<xforms:label class="all-label">
Color:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_inspection_sticker"
incremental="true">
<xforms:label class="all-label">
Inspection Sticker:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_license_plate"
incremental="true">
<xforms:label class="all-label">
Licence Plate:
</xforms:label>
</xforms:input>
</xhtml:td>
<xhtml:td class="form-td">
<xforms:input
ref="instance('taskinput')/fe:vehicle_state_issued"
incremental="true">
<xforms:label class="all-label">
State Issued:
</xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
</xhtml:table>
</xhtml:fieldset>
<xhtml:div id="xforms_cntrl_take_defendant">
<xforms:select1 appearance="minimal" ref="instance('taskoutput')/
fe:take_defendant">
<xforms:label>Are you taking Defendant to ALLEGHENY COUNTY JAIL or
Local MJJ / Arraignment Court: </xforms:label>
<xforms:item>
<xforms:label>undefined</xforms:label>
<xforms:value>undefined_value</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div
id="xforms_cntrl_Affiant_and__or_other_Police_Officers_Text">
<xforms:output ref="instance('taskoutput')/
fe:Affiant_and__or_other_Police_Officers_Text">
<xforms:label>Affiant and / or other Police Officers corroborated
details of the information</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_This_source_made_declaration_Text">
<xforms:output ref="instance('taskoutput')/
fe:This_source_made_declaration_Text">
<xforms:label>This source made declaration against his / her penal
interest to the above offense</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Source_has_given_information_Text">
<xforms:output ref="instance('taskoutput')/
fe:Source_has_given_information_Text">
<xforms:label>Source has given information in the past which has
led to arrest and / or conviction </xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Defendants_reputation_Text">
<xforms:output ref="instance('taskoutput')/
fe:Defendants_reputation_Text">
<xforms:label>Defendant's reputation for criminal activity</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Source_is_presumed_reliable_Text">
<xforms:output ref="instance('taskoutput')/
fe:Source_is_presumed_reliable_Text">
<xforms:label>Source is presumed reliable; i.e., other Police
Officer, Eyewitness, Victim of Crime, etc. </xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_source_presumed">
<xforms:select appearance="full" ref="instance('taskoutput')/
fe:source_presumed">
<xforms:item>
<xforms:label>undefined</xforms:label>
<xforms:value>undefined_value</xforms:value>
</xforms:item>
</xforms:select>
</xhtml:div>
<xhtml:div id="xforms_cntrl_source_information">
<xforms:select appearance="full" ref="instance('taskoutput')/
fe:source_information">
<xforms:item>
<xforms:label>undefined</xforms:label>
<xforms:value>undefined_value</xforms:value>
</xforms:item>
</xforms:select>
</xhtml:div>
<xhtml:div id="xforms_cntrl_defendant_reputation">
<xforms:select appearance="full" ref="instance('taskoutput')/
fe:defendant_reputation">
<xforms:item>
<xforms:label>undefined</xforms:label>
<xforms:value>undefined_value</xforms:value>
</xforms:item>
</xforms:select>
</xhtml:div>
<xhtml:div id="xforms_cntrl_source_declaration">
<xforms:select appearance="full" ref="instance('taskoutput')/
fe:source_declaration">
<xforms:item>
<xforms:label>undefined</xforms:label>
<xforms:value>undefined_value</xforms:value>
</xforms:item>
</xforms:select>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affiant_corroborates">
<xforms:select appearance="full" ref="instance('taskoutput')/
fe:affiant_corroborates">
<xforms:item>
<xforms:label>undefined</xforms:label>
<xforms:value>undefined_value</xforms:value>
</xforms:item>
</xforms:select>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Please_check_all_that_apply_Text">
<xforms:output ref="instance('taskoutput')/fe:Please_check_all_that_apply_Text">
<xforms:label>(Please check all that apply)</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_why_affiant_believes_Text">
<xforms:output ref="instance('taskoutput')/
fe:why_affiant_believes_Text">
<xforms:label>WHY AFFIANT BELIEVES THE SOURCE OF INFORMATION:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Refresh_Offenses_Text">
<xforms:output ref="instance('taskoutput')/
fe:Refresh_Offenses_Text">
<xforms:label>[ Refresh Offenses]</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_controls_save">
<xforms:select1 appearance="compact" ref="instance('taskoutput')/
fe:controls_save">
<xforms:label>SELECT ONE: </xforms:label>
<xforms:item>
<xforms:label>Print Complaint Draft</xforms:label>
<xforms:value>DRAFT</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Accept & Print Final Complaint</xforms:label>
<xforms:value>FINAL</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Edit Record</xforms:label>
<xforms:value>EDIT</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Return to PickList</xforms:label>
<xforms:value>PICKLIST</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_super_review_decision">
<xforms:select1 appearance="minimal" ref="instance('taskoutput')/
fe:super_review_decision">
<xforms:item>
<xforms:label>Approved</xforms:label>
<xforms:value>APPROVED</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Changes Required</xforms:label>
<xforms:value>CHANGES</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Denied</xforms:label>
<xforms:value>DENIED</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Supervisor_Review_Decision_Text">
<xforms:output ref="instance('taskoutput')/
fe:Supervisor_Review_Decision_Text">
<xforms:label>Supervisor Review Decision:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_SUPERVISOR_REVIEW_Text">
<xforms:output ref="instance('taskoutput')/
fe:SUPERVISOR_REVIEW_Text">
<xforms:label>SUPERVISOR REVIEW:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_super_review_comments">
<xforms:textarea ref="instance('taskoutput')/
fe:super_review_comments"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_da_review_decision">
<xforms:select1 appearance="minimal" ref="instance('taskoutput')/
fe:da_review_decision">
<xforms:item>
<xforms:label>Approved</xforms:label>
<xforms:value>APPROVED</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Changes Required</xforms:label>
<xforms:value>CHANGES</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Denied</xforms:label>
<xforms:value>DENIED</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Not Applicable</xforms:label>
<xforms:value>NA</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_DA_Decision_Text">
<xforms:output ref="instance('taskoutput')/fe:DA_Decision_Text">
<xforms:label>D.A. Review Decision:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_DA_REVIEW_Text">
<xforms:output ref="instance('taskoutput')/fe:DA_REVIEW_Text">
<xforms:label>D.A. REVIEW:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_da_review_comments">
<xforms:textarea ref="instance('taskoutput')/
fe:da_review_comments"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_id_otn">
<xforms:input ref="instance('taskoutput')/fe:id_otn">
<xforms:label>OTN: </xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_id_idnum">
<xforms:input ref="instance('taskoutput')/fe:id_idnum">
<xforms:label>ID No:</xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_magistrate">
<xforms:input ref="instance('taskoutput')/
fe:affadavit_magistrate">
<xforms:label>Magisterial District Justice:</xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_address_county">
<xforms:input ref="instance('taskoutput')/fe:address_county">
<xforms:label>County</xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_phys_desc_build">
</xhtml:div>
<xhtml:div id="xforms_cntrl_arrest_classification">
<xforms:input ref="instance('taskoutput')/
fe:arrest_classification">
<xforms:label>Arrest Classification:</xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_officer_name">
<xforms:input ref="instance('taskoutput')/fe:officer_name">
<xforms:label>Officer Name:</xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_arrest_type">
<xforms:select1 appearance="minimal" ref="instance('taskoutput')/
fe:arrest_type">
<xforms:label>Arrest Type:</xforms:label>
<xforms:item>
<xforms:label>On-View Arrest</xforms:label>
<xforms:value>ARREST</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Warrant Request</xforms:label>
<xforms:value>WARRANT</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>Summons</xforms:label>
<xforms:value>SUMMONS</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_officer_department">
<xforms:select1 appearance="minimal" ref="instance('taskoutput')/
fe:officer_department">
<xforms:label>Department:</xforms:label>
<xforms:item>
<xforms:label>Allegheney County P.D.</xforms:label>
<xforms:value>ALLEGHENY</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>City of Pittsburgh P.D.</xforms:label>
<xforms:value>PITTSBURGH</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_sent_to">
<xforms:output ref="instance('taskoutput')/fe:sent_to"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_id_ccr">
<xforms:input ref="instance('taskoutput')/fe:id_ccr">
<xforms:label>Dept. Incident No:</xforms:label>
</xforms:input>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_accuse_unknown">
<xforms:select1 appearance="full" ref="instance('taskoutput')/
fe:affadavit_accuse_unknown">
<xforms:item>
<xforms:label>true</xforms:label>
<xforms:value>1</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>false</xforms:label>
<xforms:value>0</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_narrative">
<xforms:textarea ref="instance('taskoutput')/
fe:affadavit_narrative"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_I_accuse_John_Doe_Text">
<xforms:output ref="instance('taskoutput')/
fe:I_accuse_John_Doe_Text">
<xforms:label>I accuse the defendant whose name and popular
designation or nickname is unknown to me and who I have therefore
designated as John Doe:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_I_accuse_name_unknown_Text">
<xforms:output ref="instance('taskoutput')/
fe:I_accuse_name_unknown_Text">
<xforms:label>I accuse the defendant whose name is unknown to me
but who is described as:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_I_accuse_the_above_Text">
<xforms:output ref="instance('taskoutput')/
fe:I_accuse_the_above_Text">
<xforms:label>I accuse the above named defendant:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_accuse_above">
<xforms:select1 appearance="full" ref="instance('taskoutput')/
fe:affadavit_accuse_above">
<xforms:item>
<xforms:label>true</xforms:label>
<xforms:value>1</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>false</xforms:label>
<xforms:value>0</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Spell_Check_Aff_Text">
<xforms:output ref="instance('taskoutput')/
fe:Spell_Check_Aff_Text">
<xforms:label>[Spell check Affadavit Narrative]</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_AFFADAVIT_NARRATIVE_Text">
<xforms:output ref="instance('taskoutput')/
fe:AFFADAVIT_NARRATIVE_Text">
<xforms:label>AFFADAVIT NARRATIVE:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_date_how_both_know">
<xforms:textarea ref="instance('taskoutput')/
fe:affadavit_date_how_both_know"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_How_both_knows_Text">
<xforms:output ref="instance('taskoutput')/
fe:How_both_knows_Text">
<xforms:label>How both Affiant and/or source of information knows
that a particular crime has been committed:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_how_source_knows">
<xforms:textarea ref="instance('taskoutput')/
fe:affadavit_how_source_knows"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_How_source_knows_Text">
<xforms:output ref="instance('taskoutput')/
fe:How_source_knows_Text">
<xforms:label>How the source of information knows this particular
person committed the crime:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_how_affiant_knows">
<xforms:textarea ref="instance('taskoutput')/
fe:affadavit_how_affiant_knows"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_How_Affiant_knows_Text">
<xforms:output ref="instance('taskoutput')/
fe:How_Affiant_knows_Text">
<xforms:label>How Affiant knows this particular person committed
crime: (personal observation, defendant's admissions, etc.)</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Same_as_Arrest_Date_Text2">
<xforms:output ref="instance('taskoutput')/
fe:Same_as_Arrest_Date_Text2">
<xforms:label>[Same as Arrest Date]</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_date_source_received_info">
<xforms:input ref="instance('taskoutput')/
fe:affadavit_date_source_received_info"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Date_source_received_info_Text">
<xforms:output ref="instance('taskoutput')/
fe:Date_source_received_info_Text">
<xforms:label>Date when the source of information (Police
Officers, Informant, Victim, Co-Defendant, Defendant, etc.) received
information:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Same_as_Arrest_Date_Text">
<xforms:output ref="instance('taskoutput')/
fe:Same_as_Arrest_Date_Text">
<xforms:label>[Same as Arrest Date]</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_date_affiant_received_info">
<xforms:input ref="instance('taskoutput')/
fe:affadavit_date_affiant_received_info"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Date_Affiant_received_info_Text">
<xforms:output ref="instance('taskoutput')/
fe:Date_Affiant_received_info_Text">
<xforms:label>Date when Affiant received information:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_WHEN_Text">
<xforms:output ref="instance('taskoutput')/fe:WHEN_Text">
<xforms:label>WHEN:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_HOW_Text">
<xforms:output ref="instance('taskoutput')/fe:HOW_Text">
<xforms:label>HOW:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_AFFADAVIT_INFORMATION_Text">
<xforms:output ref="instance('taskoutput')/
fe:AFFADAVIT_INFORMATION_Text">
<xforms:label>AFFADAVIT INFORMATION:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_other_participants">
<xforms:textarea ref="instance('taskoutput')/
fe:affadavit_other_participants"/>
</xhtml:div>
<xhtml:div
id="xforms_cntrl_Other_Participants_Do_not_include_above_Defendant">
<xforms:output ref="instance('taskoutput')/
fe:Other_Participants_Do_not_include_above_Defendant">
<xforms:label>Other Participants (Do not include above
Defendant):</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_accuse_doe">
<xforms:select1 appearance="full" ref="instance('taskoutput')/
fe:affadavit_accuse_doe">
<xforms:item>
<xforms:label>true</xforms:label>
<xforms:value>1</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>false</xforms:label>
<xforms:value>2</xforms:value>
</xforms:item>
</xforms:select1>
</xhtml:div>
<xhtml:div id="xforms_cntrl_affadavit_unknown_desc">
<xforms:textarea ref="instance('taskoutput')/
fe:affadavit_unknown_desc"/>
</xhtml:div>
<xhtml:div id="xforms_cntrl_COMPLAINT_INFORMATION_Text">
<xforms:output ref="instance('taskoutput')/
fe:COMPLAINT_INFORMATION_Text">
<xforms:label>COMPLAINT INFORMATION:</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_Create_Offenses_Text">
<xforms:output ref="instance('taskoutput')/
fe:Create_Offenses_Text">
<xforms:label>[Create Offenses Table]</xforms:label>
</xforms:output>
</xhtml:div>
<xhtml:div id="xforms_cntrl_ADDVIEW_ALIASES_Text">
<xforms:output ref="instance('taskoutput')/
fe:ADDVIEW_ALIASES_Text">
<xforms:label>[ADD/VIEW ALIASES]</xforms:label>
</xforms:output>
</xhtml:div> -->
</xhtml:body>
</xhtml:html>
CSS tables
This is an example of using CSS to format a table without actually using the HTML table element. This is critical since some browsers do not support dynamic tabular layout. The Firefox 0.6 extension also does not support the repeat-nodeset attribute, so you can not yet display repeating data inside HTML tables.
The biggest drawback to this solution is that the width of the tables must be predefined in a stylesheet and can not adjust the width of the columns based on the width of the data in each row.
Program Image
[edit | edit source]Program Example
[edit | edit source]<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>Table with CSS and Divs</title>
<style type="text/css">
* {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
}
/* Example of doing layout of a table without using the HTML table tags */
.table {
display: table;
}
.tableHeader, .tableRow, .tableFooter {
display: table-row;
}
.leftHeaderCell, .leftCell, .leftFooterCell,
.rightHeaderCell, .rightCell, .rightFooterCell
{
display: table-cell;
}
.leftHeaderCell, .rightHeaderCell, .leftFooterCell {
background-color: green;
color: white;
font-weight: bold;
padding: 0 5px 0 10px;
}
.leftHeaderCell, .rightHeaderCell {
text-align: center;
}
.leftCell {
padding: 0 5px 0 10px;
}
.rightCell {
text-align: right;
}
.rightFooterCell {
text-align: right;
border-top: solid black 2px;
font-weight: bold;
}
/* Draw even rows with a light green */
.even {
color: black;
background-color: #CCFFCC;
}
</style>
</head>
<body>
<p>Table with CSS and divs</p>
<div class="table">
<div class="tableHeader">
<div class="leftHeaderCell">Description</div>
<div class="rightHeaderCell">Value</div>
</div>
<div class="tableRow">
<div class="leftCell">Item one</div>
<div class="rightCell">$1,000.00</div>
</div>
<div class="tableRow even">
<div class="leftCell">Item two</div>
<div class="rightCell">$2,000.00</div>
</div>
<div class="tableRow">
<div class="leftCell">Item three</div>
<div class="rightCell">$3,000.00</div>
</div>
<div class="tableRow even">
<div class="leftCell">Item four</div>
<div class="rightCell">$4,000.00</div>
</div>
<div class="tableRow">
<div class="leftCell">Item five has a long description</div>
<div class="rightCell">$1,000.00</div>
</div>
<div class="tableFooter">
<div class="leftFooterCell">Total: </div>
<div class="rightFooterCell">$11,000.00</div>
</div>
</div>
</body>
</html>
Custom Controls
Motivation
[edit | edit source]Very often complex forms need functionality that go beyond the basics offered by the W3C XForm standard. The good news is that XForms is designed to be easy to extend. This process is called creating a Custom Control.
There are several reason to create XForms custom controls:
- custom presentation - XForms controls as rendered by your XForms processor do not provide the right presentation for your form
- custom data types and date type to UI mappings - existing XForms controls do now work properly with your data types (for example binding a boolean to a check box)
- advanced XForms controls - you need customized controls to extend the functional of the base XForms controls
- new host language - you'd like to support XForms in host languages
The following example uses a technology called XML Bindings to create a new control. This control displays a different image when a select1 list is selected.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Custom Image Control Sample</title>
<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" />
</html:div>
</content>
<implementation implements="nsIXFormsUIWidget">
<method name="refresh">
<body>
<!--
set the src attribute on the html:img to be the simpleContent
of the instance node bound to this control
-->
var img = document.getAnonymousElementByAttribute(this, "anonid", "content");
img.setAttribute("src", this.stringValue);
return true;
</body>
</method>
</implementation>
</binding>
</bindings>
<xf:model>
<xf:instance xmlns="">
<data>
<curimg />
<img label="Firefox">http://www.mozilla.org/foundation/identity-guidelines/firefox-128.png</img>
<img label="Thunderbird">http://www.mozilla.org/foundation/identity-guidelines/thunderbird-128.png</img>
<img label="Bugzilla">http://www.mozilla.org/images/p-bugz.gif</img>
<img label="Mozilla">http://www.mozilla.org/images/mozhead-80x64.gif</img>
</data>
</xf:instance>
</xf:model>
<style type="text/css">
@namespace xf url(http://www.w3.org/2002/xforms);
xf|output[mediatype="image/*"] {
-moz-binding: url('#output-image');
}
</style>
</head>
<body>
<h1>Custom Control Sample</h1>
<xf:select1 ref="curimg">
<xf:label>Select image to display: </xf:label>
<xf:itemset nodeset="../img">
<xf:label ref="@label" />
<xf:value ref="." />
</xf:itemset>
</xf:select1>
<xf:output ref="curimg" mediatype="image/*" />
</body>
</html>
Discussion
[edit | edit source]This example uses the xbl:binding structure, a few lines of JavaScript and a binding in the CSS file. Note that example will only work within FireFox since XML bindings are not currently part of the XForms specification.
Note that the XML Binding Language (xbl) in currently a w3C working draft. See XBL working draft. When XBL becomes a recommendation these examples may have a better chance to run in multiple implementations of XForms. Right now we need to use implementation specific tags.
References
[edit | edit source]This example program was posted on the FireFox XForms documentation web site in July 2005 by Allan Beaufour: XForms Custom Controls
Warn on Navigate Away
Motivation
[edit | edit source]Sample Program
[edit | edit source]Preventing Form Data Loss When User Navigate Away from Unsaved Data
[edit | edit source]Add this code to global.js
<script type="text/javascript">
// adding a gmail style function to stop the user from moving away from the page..
function unloadMessage(){message = "This form has not yet been submitted to the database\nAll data will be lost."
return message;}
function setBunload(on){window.onbeforeunload = (on) ? unloadMessage : null;}
setBunload(true);
</script>
Mozilla Page [10]
IE Manual [11]
Discussion
[edit | edit source]Use the xf:load action in combination with an xforms-value-changed event to call a "dirty" function containing setBunload(true).
Likewise, use the load action within the submission to call a "clean" function containing "setBunload(false)".
function dirty() {
setBunload(true);
}
function clean() {
setBunload(false);
}
This one goes in your "submission" element:
<xf:load resource="javascript:clean()" ev:event="xforms-submit-done"/>
and this
<xf:load resource="javascript:dirty()" ev:event="xforms-value-changed"/>
goes somewhere in the form - place it at the body-level to capture all change events, or nest it within a more appropriate container.
References
[edit | edit source]This example was taken from Alex Bleasdale in 2007.
Microsoft documentation on page unload function
Select All
WARNING THIS EXAMPLE IN DEVELOPMENT
[edit | edit source]Motivation
[edit | edit source]You would like to be able to select all rows in a table using a single trigger.
Approach
[edit | edit source]You can put a list of items in a table and have a single column that has a checkbox in it. You can then use the index function to change the selected item.
Screen Image
[edit | edit source]Sample Program
[edit | edit source]<?xml version="1.0"?>
<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"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Select all, Unselect all</title>
<style type="text/css">
table {width:300px}
td,td {text-align: center; width:25%}
</style>
<xf:model>
<xf:instance xmlns="">
<data>
<item id="1" selected="false">
<title>red</title>
</item>
<item id="2" selected="false">
<title>orange</title>
</item>
<item id="3" selected="false">
<title>yellow</title>
</item>
<item id="4" selected="false">
<title>blue</title>
</item>
</data>
</xf:instance>
<xf:bind nodeset="item/@selected" type="xs:boolean" />
</xf:model>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>position()</th>
<th>index()</th>
<th>color</th>
<th>select</th>
</tr>
</thead>
</table>
<!-- one table per row :-( -->
<xf:repeat nodeset="item" id="repeat-id">
<table>
<tr>
<td>
<xf:output value="position()" />
</td>
<td>
<xf:output value="index('repeat-id')" />
</td>
<td>
<xf:output ref="title" />
</td>
<td>
<xf:input ref="@selected" />
</td>
</tr>
</table>
</xf:repeat>
<xf:trigger>
<xf:label>Select all list [n]</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="item[1]/@selected" value="'true'" />
<xf:setvalue ref="item[2]/@selected" value="'true'" />
<xf:setvalue ref="item[3]/@selected" value="'true'" />
<xf:setvalue ref="item[4]/@selected" value="'true'" />
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Unselect all list [n]</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="item[1]/@selected" value="'false'" />
<xf:setvalue ref="item[2]/@selected" value="'false'" />
<xf:setvalue ref="item[3]/@selected" value="'false'" />
<xf:setvalue ref="item[4]/@selected" value="'false'" />
</xf:action>
</xf:trigger>
<br />
<xf:trigger>
<xf:label>Select all repeat</xf:label>
<xf:action ev:event="DOMActivate">
<xf:repeat nodeset="item" id="repeat-id-2">
<xf:setvalue ref="@selected" value="'true'" />
</xf:repeat>
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Unselect repeat</xf:label>
<xf:action ev:event="DOMActivate">
<xf:repeat nodeset="item" id="repeat-id-3">
<xf:setvalue ref="@selected" value="'false'" />
</xf:repeat>
</xf:action>
</xf:trigger>
<ol>
<xf:repeat nodeset="item" id="repeat-id-4">
<li>
<xf:output ref="@selected" />
</li>
</xf:repeat>
</ol>
</body>
</html>
Discussion
[edit | edit source]Note that the setvalues inside the repeat blocks do not work. I have tried to use the current() function inside the repeat like this:
<xf:repeat>
<xf:setvalue ref="current()/@selected" value="'false'" />
</xf:repeat>
but with no luck.
If anyone knows how to get this working, please let us know. Thanks - Dan
Alternate Way
[edit | edit source]Note: <xf:repeat> does not work inside <xf:action>. Here is the workaround for this.
<xf:instance id="count">
<count/>
</xf:instance>
<xf:bind nodeset="instance('count')" type="xs:integer" />
<xf:trigger>
<xf:label>Select all repeat</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('count')" value="0" />
<xf:action while="instance('count') < count(item)">
<xf:setvalue ref="instance('count')" value="instance('count') + 1" />
<xf:setvalue ref="item[number(instance('count'))]/@selected" value="'true'" />
</xf:action>
</xf:action>
</xf:trigger>
Google Maps
Motivation
[edit | edit source]You want to create an XForms application that displays Google Maps.
Discussion
[edit | edit source]
Sorting using XSLT
Motivation
[edit | edit source]One problem that keeps popping up when creating forms with XForms is the lack of sorting. This is an example for how it is possible to sort an instance using a XSLT stylesheet in Firefox.
Firefox XForms Example
[edit | edit source]The following model contains two instances. The first instance is the one we will sort and the second instance contains the XSLT stylesheet we will use to perform the sort.
<xf:model>
<xf:instance id="default-instance">
<data xmlns="">
<item>
<name>B-item</name>
<date>2001-05-03</date>
</item>
<item>
<name>A-item</name>
<date>2005-05-03</date>
</item>
<item>
<name>Z-item</name>
<date>2003-05-03</date>
</item>
<item>
<name>D-item</name>
<date>2002-05-03</date>
</item>
</data>
</xf:instance>
<xf:instance id="stylesheet">
<xsl:stylesheet
xmlns=""
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<data>
<xsl:apply-templates select="data/item">
<xsl:sort type="string" select="name"/>
</xsl:apply-templates>
</data>
</xsl:template>
<xsl:template match="*|@*|text()">
<xsl:copy>
<xsl:apply-templates select="*|text()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
</xf:instance>
</xf:model>
To perform the sort we will use the following JavaScript which will load the second instance into the Firefox stylesheet engine, then take the first instance make the transformation which will produce the sorted instance. Then the transformed instance is inserted into the model and a rebuild, recalculate, revalidate and refresh is performed.
function sort_instance(id) {
// We get the instance element
var instanceElement = document.getElementById(id);
if (instanceElement!=null) {
// XForms exposes the retrival of the instance document from the model element which *should*
// be the parent for the instance element.
var instance = instanceElement.parentNode.getInstanceDocument(id);
if (instance!=null) {
// Now creating the stylesheet, for this example the stylesheet document is also an instance
// but it can be loaded from many difference sources
var xslDom = instanceElement.parentNode.getInstanceDocument('stylesheet');
// create an XSLTProcessor and attach the stylesheet
var processor = new XSLTProcessor()
processor.importStylesheet(xslDom);
// now we do the sorting transformation
var resultDom = processor.transformToDocument(instance, instance);
// we then move the result info the instance dom
instance.removeChild(instance.documentElement);
instance.appendChild(resultDom.documentElement);
// and performs the updates for XForms
instanceElement.parentNode.rebuild();
instanceElement.parentNode.recalculate();
instanceElement.parentNode.revalidate();
instanceElement.parentNode.refresh();
}
}
}
Discussion
[edit | edit source]The idea of having the stylesheet in an instance makes it possible to change the behavior of the sorting by binding controls to it and change stuff like XPath expressions and other XSLT syntax.
References
[edit | edit source]This example is based upon the sample on [[12]http://landwehr.dk/blog/]
Mobile XForms
Advantages to the Developer
[edit | edit source]Apart from the advantages of XForms already cited elsewhere, XForms brings the following advantages to the sphere of mobile applications:
- XForms was designed to support multiple modalities. Applications that work on mobile devices are also deployable in other ways too, thus much improving the return on your development investment.
- XForms does most of its work on the client-side, thus reducing the number and size of server calls. This is still an important consideration for mobile devices, which tend to have to operate on narrow and expensive bandwidth.
Building Mobile Applications
[edit | edit source]Whilst there is a Basic profile of XForms, the only known, commercial implementation also supports almost the entire XForms/XML Schema feature set.
Open Source Implementations
[edit | edit source]Xfolite
[edit | edit source]Xfolite is a light-weight XForms client for the J2ME platform. It was originally created at Nokia Research Center, and it includes a DOM and XPath 1.0 implementation as well as an XForms engine that implements the XForms 1.1 specification almost completely. XML Schemas and CSS are outside project scope, however. Xfolite is licensed under the LGPL license.
Commercial Implementations
[edit | edit source]PicoForms
[edit | edit source]PicoForms has an XForms implementation that runs on cell phones supporting MIDP 2.0 and CLDC 1.x. It also supports PDAs including Palm and Pocket PCs. PicoForms is also able to provide customers (and evaluators) with an online development space, that allows forms to be tested on a mobile phone/PDA emulator.
Picoforms runs as an plugin to Internet Explorer. The license is around $30 (US) per client (desktop).
To enable your forms to work with Picoforms just add the following line to your code:
<?import namespace="xf" implementation="#default#pxf"?>
Sample Applications for PicoForms
[edit | edit source]UK Pension Industry
[edit | edit source]This application uses a set of industry standard XML schema (produced by Origo Services) in the UK. XForms lends itself well to building applications over such schema, as the schema can be consumed directly by the application, often without modification.
The Scenario
[edit | edit source]The Schemas describe the data requirements for a financial adviser requesting information about the value of funds in a customer's personal pension policy. An adviser is likely to want to do this immediately prior to meeting with their client, probably in the client's own home. They want the information to be as up-to-date as possible.
The Application
[edit | edit source]The following screenshots give an idea of the application running on a mobile phone emulator. The application can be accessed in an emulator here.
To begin with the user must search for the details of the client they are interested in. This simulates communication with the adviser's own back-office system. This can be achieved either by entering a unique reference for the client, or the client's name.
Discussion
[edit | edit source]
FireFox Extension
Motivation
[edit | edit source]Your users all can run the FireFox browser on MS-Windows and you want very fast XForms loading.
The Mozilla Firefox Plugin
[edit | edit source]This plugin was developed over several years with the support of IBM and Novell. It is now obsolete and is no longer supported.
The official version is available from addons.mozilla.org.
Nightly and other (testing) builds are available at Philipp Wagner's Web Site
References
[edit | edit source]- Mozilla FireFox XForms page Note that this web page was last updated in April 14th, 2014.
Discussion
[edit | edit source]
Picoforms
Getting XForms to work with Picoforms
[edit | edit source]Picoforms is commercial XForms client that is designed to work with mobile phones and IE 6.0 as a plugin.
To get IE to see the forms you have to do the following:
If your forms are stored in the server with an XHTML extension you must
- Make sure that IE knows to render .XHTML files as html file types. This can be done by using the registry edit tool.
- Add the following processing instruction for picoforms AFTER the html element
IE 6.0 Registry MIME-Type Fix
[edit | edit source]To change the IE registry to allow IE to know that .xhtml files should be rendered as html. To do this do the following. From the Windows start menu click Start/Run. Enter "regedit" and press enter. Use the Registry browser to navigate to the HKEY_CLASSES_ROOT folder and then find the MIME/Daatabase/Content Type folder.
From their add the following:
Binding for xhtml files:
[HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/xhtml+xml] "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" "Extension"=".xhtml" "Encoding"=hex:08,00,00,00
Binding for xq files:
[HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/xhtml+xml] "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" "Extension"=".xq" "Encoding"=hex:08,00,00,00
The CLSID above is for HTML rendering. You can copy this from the .htm MIME-type. If you want it to render in xml use the binding for XML files.
Sample HTML Header
[edit | edit source]<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" >
<?import namespace="xf" implementation="#default#pxf"?>
<head>
...
Note that if you are using eXist to generate your forms you need to put the PI inside braces and serialize as html.
declare option exist:serialize "method=html media-type=text/html indent=yes omit-xml-declaration=yes";
...
<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" >
{<?import namespace="xf" implementation="#default#pxf"?>}
<head>...
Also, make sure if you make changes you should be sure to use SHIFT-reload to clear the IE cache.
CSS Issues
[edit | edit source]Note that IE6 does not recognize the @namepsace directive in CSS files. These CSS files will need to be converted use xf\: instead of the CSS | standard.
References
[edit | edit source]
Apache
The Apache web server is the most popular web server on the Internet. It provides high-performance web pages serving and is very secure.
By default, the out-of-the box Apache server does not allow users to write files to a web server. This is done for security reasons.
WARNING: The following should only be used on Intranet servers and should be reviewed by security professionals in your organizations.
Steps to Configure Apache HTTP Server to Enable "PUT" Operations
[edit | edit source]- Download and install the HTTP Server from apache.org. I am using v2.2.4
- Verify that it is serving up regular xhtml files like you think it should
- Stop the service
- In your httpd.conf uncomment the LoadModule for dav_module and dav_fs_module also uncomment the line "Include conf/extra/httpd-dav.conf" so that the httpd-dav.conf is loaded
- edit conf/extras/httpd-dav.conf and change the 'uploads' alias and directory to be what you want them to be. They should match, of course.
- To authenticate users you can use the htpasswd command line program to create the password and put it in the uploads directory. Of course, you can also disable password protection during the testing phase of your project.
Sample httpd-dav.conf file
[edit | edit source]This is what the beginning of my httpd-dav.conf looked like when it was done:
DavLockDB "E:/httpd/Apache2.2/var/DavLock" Alias /uploads "C:/www/xforms/uploads" <Directory "C:/www/xforms/uploads"> Dav On Order Allow,Deny Allow from all #AuthType Digest AuthType Basic AuthName DAV-upload # You can use the htdigest program to create the password database: # htdigest -c "E:/httpd/Apache2.2/user.passwd" DAV-upload admin # AR: I used htpasswd -> htpasswd -c "C:/www/xforms/uploads/user.passwd" admin #AuthUserFile "E:/httpd/Apache2.2/user.passwd" AuthUserFile "C:/www/xforms/uploads/user.passwd" # Allow universal read-access, but writes are restricted # to the admin user. <LimitExcept GET OPTIONS> require user admin </LimitExcept> </Directory>
Restarting Apache
[edit | edit source]After you make any changes to the Apache config files you must restart Apache using the Apache restart command such as:
apachectl restart
or
apachectl stop apachectl start
If you have problems, make sure to check the Apache log file. If you get errors you may not have the permissions set correctly for the folder that your form is writing to.
Checking the Access Log File
[edit | edit source]If your forms do not save, you can also check the Apache access log files. They are usually located in a directory such as:
Windows: C:\Program Files\Apache Software Foundation\Apache2.2\logs\access.log
If you see a line such as:
192.168.1.105 - - [08/Feb/2007:16:58:01 -0600] "PUT /forms/data.xml HTTP/1.1" 405 235
This indicates that you are getting a HTTP 405 error: Method Not Allowed. A 405 status code is returned when the client has tried to use a "request method" such as PUT or POST that the server does not allow. This means you don't yet have your configuration correct and that your XForms will not save its data.
References
[edit | edit source]This example was suggested by Aaron Reed from IBM Corporation Austin TX.
Versioning Form Data With WebDAV and Subversion
Motivation
[edit | edit source]Users frequently want multi-versioned forms. This means that they not only want to keep prior versions of a form's instance data but they also want to:
- be able to view prior versions
- compare the current version with a prior version
- see who changed what fields on a form an when
- revert to a prior version
This problem frequently occurs in complex computer systems that have configuration files. Something stops working but people don't notice it till later. There is no information about what the prior versions of configuration file looked like so the entire systems must be restored from backups. Many of these problems could be avoided by automatically reverting to the prior version of a configuration file.
Background
[edit | edit source]With the XForms standard we are given the <submission> element and a small list of HTTP operators (GET, PUT, POST) to use and an action that can be any URL. If we want to allow users to save form data to a version-control system or to see prior versions of a form we have to translate these operations into something that a web server will recognize as operations on a version-control database.
Subversion is an open-source version control system with a client/server architecture (as opposed to a file-based architecture typical of other version controls systems).
Unlike older file-based version control systems, Subversion uses a transaction server model similar those used for reliable banking transactions. This makes subversion very reliable and allows you to check-in (or commit) groups of files that should be checked in together. They will either all succeed or all fail but the version controls system is guaranteed to always be in a consistent state.
Subversion also conforms (where it can) to the WebDAV WebDAV stands for Web Distributed Authoring and Versioning specification. The standard web HTTP protocol supports just a few operations such as get, put and post. WebDAV extends these simple operations to include operations we might expect on a file system such as delete, move and copy. Since WebDAV is more about file operations and Subversion is more centered on transactions, sometimes there is not an exact fit between the two.
Subversion has two principal concepts:
- update - gets the latest version of your code from the server.
- commit - take all the files you have changed from your local file system and save the changes through a transaction on the server.
To allow forms data to save to subversion we need to make a submission element do a commit. This is not necessarily hard but we want to be clear how the systems are different.
Subversion, WebDAV
[edit | edit source]Subversion is a version control database. At its core, it does not include an independent access control system. Because it is usually installed as part of a web server it usually uses the access control system of the web server it runs on. Apache also supports the WebDAV HTTP extensions which allow complex operations beyond the basic HTTP get, put and post. One of the best ways to get XForms to be persistent is to configure Apache to use WebDAV with
Autoversioning and Apache
[edit | edit source]To configure autoversioning with Apache2 server you must modify the configuration file. This file should be configured to support your XForms work.
WARNING!: Any time you allow public access to write to your server you are dealing with security issues. You should always consider ALL of the security implications before you make ANY changes to a web servers configuration file. Make sure that security professional in your organization review any systems that have public web access.
You will want to have an Apache configuration similar to the following somewhat half-XMLish format:
<Location /repos> DAV svn SVNPath /var/svnrepos SVNAutoversioning on <LimitExcept GET PUT POST PROPFIND OPTIONS REPORT> Require valid-user </LimitExcept> </Location>
See also the well-written chapter of the Subversion Red Book or the respective excellent Gentoo 's Apache-SVN-WebDAV-HOWTO section for detailed configuration help with examples.
Converting HTTP PUT into Subversion Submit
[edit | edit source]The last step is to convert HTTP PUT into a subversion COMMIT. This can be accomplished using a program such as Jetty.
(We will post a sample program soon).
ViewCV and ReST
[edit | edit source]You can also start to add tools to Apache and Subversion to get colorful output that shows the differences between prior files. One option is to add the ViewVC (View Version Control) system to your Apache server. ViewVC allows you to see version history can compare prior versions just by addeing parameters to the URL. This method of using the URL to pass parameters to a server program is frequently called a REST interface. Almost all REST interfaces are easy to interface with XForms <submission> since XForms can encode the submission instances directly onto the URL.
Subversion REST URL interface
[edit | edit source]Subversion allows you to access a resource's version history by adding an additional path to the URL. See [13]
For example if your file name was
http://www.example.com/my-repository/myfile.xml
If you wanted to get version 47 of a file it might be:
http://www.example.com/my-repository/!svn/ver/47/myfile.xml
Debugging Tips
[edit | edit source]The Subversion FAQ suggests you run the Wireshark packet sniffer and look at the data in the HTTP messages. You can also use the Charles Web debugging proxy which also has a nice FireFox plug-in. Just make sure you know how to disable the proxy by going to the Firefox Tools/Options/General/Connection Settings and click the Direction Connection to the Internet. If you do not your web browser will no longer function when Charles shuts down.
References
[edit | edit source]DRAFT of webDAV usage with subversion
Subversion source code stored in Subversion
IIS
The authors have not yet tried to configure IIS to work with XForms but there is plenty of documentation on the web about how to do this. One example is:
This example includes screen images of the IIS administration tool.
IIS also has an access log file that will put 405 errors in it if there are still problems.
Any contributions would be helpful.
Discussion
[edit | edit source]
XML Databases
Native XML Databases
[edit | edit source]XForms works very well when the submit element can insert or update instance data directly into a database. This feature is supported by most native and hybrid databases.
There are over 30 Native XML databases in use today from both OpenSource and commercial vendors. One of the large factors that make some easier to integrate with XForms is the availability of a Rest interface so that your submit URL statement can be structured somewhat like this:
http://www.example.com/application/form/save.xq
Where save is some XQuery file that has the instructions for saving the XML data into the appropriate table or collection.
References
[edit | edit source]For a list of Native XML Databases see:
eXist
eXist is a native XML database that has a full REST interface. This allows you to use eXist to save form data without writing any middleware glue.
eXist REST interface
[edit | edit source]eXist provides a full REST interface that is easy to call from an XForm.
eXist WebDAV interface
[edit | edit source]eXist also provides a full WebDAV interface. This allows you to do HTTP "PUT" operations directly from your forms.
eXist Example
[edit | edit source]In this example, we will create a user named "juser" (Jane User) and setup a collection to read and write form data.
Sample Program
[edit | edit source]To run this program, just install eXist from the [15] web site. use the eXist admin menu to create a user called "juser". Then create a home collection for juser at /db/home/juser. Then login as juser and create a collection called "test". You will put a form and instance data into this file.
To read and write instance data into a form just use the following example:
<html>
<head>
<xf:model>
<xf:instance id="data-instance" src="data.xml" xmlns=""/>
<xf:submission id="read-from-file"
method="get"
action="http://localhost:8080/exist/rest/db/home/juser/test/data.xml"
replace="instance" instance="data-instance"/>
<xf:submission id="save-to-file"
method="put"
action="http://localhost:8080/exist/webdav/db/home/juser/test/data.xml"
replace="instance" instance="data-instance"/>
</xf:model>
</head>
...
Note that if the data is in the same collection as the form (not a good long term design) you can use a relative path reference. Also note that we are doing an HTTP PUT operation to the webdav (not rest) interface to exist.
Using eXist URLs
[edit | edit source]It is easy to load XML data directly into your XForms application. In the instance statement in your model just add a src attribute and put a path name to the file you want to edit. The key is to put the word "rest" in the URL when you are reading data into your form:
<xf:instance id="my-form-data" xmlns="" src="http://localhost:8080/exist/rest/db/home/juser/test/data.xml"/>
Always put the word "webdav" in the URL path when doing an HTTP PUT.
http://localhost:8080/exist/webdav/db/home/juser/test/data.xml
That is all there is to it!
For more information see the eXist manual on using the REST and WebDAV interfaces for eXist.
Using XQuery to return Document IDs
[edit | edit source]When using an XML database, you sometimes wish to have the database receive an XML document and store it in the correct location based on business rules such as the content of an XML document and the date. This can be done in relational databases using stored procedures.
XQuery can be thought of as an XML-oriented stored procedure. eXist allows you to save directly to the URL of an XQuery and the XQuery can store the document based on a number of rules.
Here is an example eXist XQuery that that takes HTTP POST and creates a path name to a collection based on the county in input document and the date. After it saves the file and checks that the save has worked it increments a counter similar to the AUTOINCREMENT property of some relational databases.
xquery version "1.0";
(: Save-crv.xq Version 0.1, Dan McCreary, March 2nd 2007:)
declare namespace request="http://exist-db.org/xquery/request";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
declare namespace c="http://niem.gov/niem/common/1.0" ;
declare namespace u="http://niem.gov/niem/universal/1.0" ;
declare namespace mn="http://data.state.mn.us" ;
declare namespace mnr="http://revenue.state.mn.us" ;
declare namespace mnr-ptx="http://propertytax.state.mn.us" ;
declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance";
(: to store a CRV into the right location in exist we need 1) the county ID, 2) the date, 3) the sequence number :)
(: get the data from an HTTP post :)
let $crv := request:get-data()
let $count := count($crv//node())
let $county-id := $crv//eCRVDocument/RealProperty/RealPropertyLegalDescriptions/mnr-ptx:MNCountyID/text()
(: let $county-id := '19' :)
let $current-year := substring(string(current-date()),1, 4)
let $current-year-2 := substring(string(current-date()),3, 2)
(: let $collection := xmldb:collection(concat('xmldb:exist:///db/crv/data', $county-id, '/', $current-year), "dan", "dan123") :)
let $county-name := doc('/db/crv/data/admin/next-county-crvid.xml')//County[CodeID=$county-id]/Code
(: get the next-id from the sequence counter :)
let $next-id := doc('/db/crv/data/admin/next-county-crvid.xml')//County[CodeID=$county-id]/NextID
let $file-name := concat($next-id, '.xml')
let $collection-string := concat('xmldb:exist:///db/crv/data/', $county-name, '/', $current-year)
let $full-path := concat($collection-string, '/', $file-name)
(: ready to login and store a file :)
let $collection := xmldb:collection($collection-string, "login", "password")
let $retStore := xmldb:store($collection-string, $file-name, <eCRVDocument>{$crv/*}</eCRVDocument>)
(: If the file that we attempted to store does eXist, then now it is OK to increment the sequence counter for the next user :)
let $retCode1 := if (doc($full-path))
then ( update replace doc("/db/crv/data/admin/next-county-crvid.xml")//County[CodeID=$county-id]/NextID with
<NextID>{$next-id + 1}</NextID> )
else ()
return
<data>
<county-id>{$county-id}</county-id>
<current-year>{$current-year-2}</current-year>
<sequence-id>{$next-id - 1}</sequence-id>
</data>
Processing the Results
[edit | edit source]This XQuery returns an XML message such as the following
<data>
<county-id>19</county-id>
<current-year>07</current-year>
<sequence-id>47</sequence-id>
</data>
Assuming you have a hostname, port and application-name variables are set up, the XForms application would contain the following code:
<xf:model>
...
<xf:submission id="submit-validate-a1" method="post"
action="http://{$hostname}:{$exist-port}/{$application-name}/submit"
replace="instance" instance="submit-result">
<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>
...
</xf:model>
...
<body>
...
<xf:case id="case-done">
<xf:group ref="instance('submit-result')">
<h1 class="result-text">Your ID is =
<xf:output ref="county-id"/>-<xf:output ref="current-year"/>-<xf:output ref="sequence-id"/></h1>
</xf:group>
...
</xf:case>
Setting the mime type for XQuery Results
[edit | edit source]If you want your XQuery to return the correct mime type put the following in the preamble:
declare option exist:serialize "method=xhtml media-type=text/xml indent=yes omit-xml-declaration=no";
declare namespace util="http://exist-db.org/xquery/util";
...
let $ret-code := util:declare-option("exist:serialize", "media-type=text/xml")
(This suggestion from Kurt Cagle)
declare option exist:serialize "method=3Dxhtml indent=3Dyes
omit-xml-declaration=3Dno
doctype-public=3D-//W3C//DTD XHTML 1.1//EN
doctype-system=3Dhttp://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd";
IBM DB2
IBM DB2 and XForms
[edit | edit source]IBM DB2 version 9 (also known as the "PureXML" release) supports both the XQuery language as well as an XML datatype. This makes it an ideal candidate for storing and retreiving your XForms instance data.
Unfortunately as of March of 2007 there is no pre-written REST interface to DB2 or a web-based administration tool for setting up and configuring DB2 XML collections.. To save your form data you will have to write some Java middleware to take the data in an HTTP POST and save it to a table in DB2 that has an XML datatype.
Here is an example from the IBM DeveloperWorks web on how to use Java to send XML data to DB2:
The good news is that once the data has been saved into DB2 you can query it using standard XQuery tools.
Form Generators
Motivation
[edit | edit source]You want to generate a user interface form directly from a model.
Method
[edit | edit source]Because XForms is a declarative XML file it can be generated by transforming a model of your data directly into a form. The most common way to store a model of hierarchical data is using an XML Schema. A server-side program will scan the XML Schema document and for each element found it will create the appropriate XForms elements.
Generated forms have the advantage over hand-crafted forms in that they can can be generated with the same set of transforms. If you change your form standards all the forms can be quickly be regenerated. Many of these advantage can be gained by pushing the formatting and layout functionality of a form into CSS style sheets. But there are also many aspects of a form that are not governed by a style sheet.
If you using a consistent naming convention in your forms you can also use this naming convention to decide what types of input controls to generate based on the information in the element name. For example simple names and amounts will map to input controls, boolean true/false values will map to inputs formatted as checkboxes, dates will use calendar selectors, text objects will use textarea controls and codes will use select or select1 controls.
Here is a sample of how ISO Data element Representation Terms map to XForms controls:
Representation Term | XForms Control |
---|---|
Amount, Name | input |
Indicator | input with type="xs:boolean" |
Date | input with type="xs:date" |
Text | Textarea |
References
[edit | edit source]Discussion
[edit | edit source]
NIEM to XForms
Motivation
[edit | edit source]You want to convert a constraint XML Schema that uses subsets generated by the US National Information Exchange Model (NIEM) directly into an XForm
References
[edit | edit source]Article by Dan McCreary on IBM Developerworks
Form Designers
<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"> <InputValueOne>3</InputValueOne> <InputValueTwo>3</InputValueTwo> </xf:instance> <xf:bind id="input-one-bind" nodeset="/Data/InputValueOne" type="xs:integer"/> <xf:bind id="input-two-bind" nodeset="/Data/InputValueTwo" type="xs:integer"/> <xf:instance id="output"> <DataOut xmlns=""> <OutputValue>9</OutputValue> </DataOut> </xf:instance> <xf:bind id="output-bind" nodeset="instance('output')/OutputValue" calculate="instance('input')/InputValueOne * instance('input')/InputValueTwo" type="xs:integer"/> </xf:model> </head> <body>
<xf:range bind="input-one-bind" start="1" end="5" step="1" incremental="true">
<xf:label>Input: </xf:label>
</xf:range>
<xf:range bind="input-two-bind" start="1" end="5" step="1" incremental="true">
<xf:label>Input: </xf:label>
</xf:range>
<xf:output bind="input-one-bind"/> * <xf:output bind="input-two-bind"/> =
<xf:output bind="output-bind"/>
</body>
</html>
Debugging XForms
If you are a newcomer to XForms and you are having problems debugging XForms you are not alone. XForms debugging can be tricky especially for newcomers. If you follow the newsgroups on XForms you will see several problems come up frequently.
Common Problems
[edit | edit source]These problems, roughly sorted in terms of frequency include the following:
- Make sure to name your files with the
.xhtml
extension. Many browsers including FireFox do not look for XML tags in files with the .htm or .html extension. - Problems related to forgetting to associate instance data with a namespace or the default namespace. This can be fixed by adding the
xmlns=""
parameter to your instance variable - Incorrect or missing namespaces in the body of a document. For example, if the default namespace is html the tag <input> is valid but the browser will look at it as <html:input> not <xf:input>. This happens frequently when users copy XForms example code from places that use XForms as the default namespace. This is a good reason that tutorial and training developers should not use XForms as the default namespace.
- Incorrect binding between the model and the view. This usually occurs because the "ref" or "nodeset" attributes are not correctly defined or that the group or repeat changes the path prefix of a data element.
- Failure to bind to the form to the instance because the XForms processor cannot find one or more instance specific namespaces. If you have customised your XForm with an XSLT or an XQuery before streaming it to your user, the processor might relegated the declaration of some of your namespaces to the instance where they first occur because it treats the contents of the ref and bind attributes on your xform as just content. However, your XForms processor probably expects the definition of the namespaces in your ref attributes to be on the parent axis and may not look in the model instances for any declarations. When this happens you will need to manually construct the root xhtml:html node, explicitly declaring any namespaces that appear in your form.
Using an XForms Validator
[edit | edit source]Some people have found this XForms validator helpful:
http://xformsinstitute.com/validator
This program will find common errors in XForms examples.
Using Eclipse to validate XPath
[edit | edit source]There is a nice eclipse plugin for XSLT providing also an XPath validation "view". See: http://wiki.eclipse.org/XSLT_Project
Debugging Tools for Firefox
[edit | edit source]One of the most useful Firefox extensions is the XForms Buddy debugger. This tool allows you to visually inspect all of the instances in the model while the XForms are running in the Firefox browser. This is especially useful for ensuring that instance values that are dynamically configured are correctly set by the XForms. The link to the site is: here
Printing your Bindings Using JavaScript
[edit | edit source]There is also a way to visually view your binding from within your JavaScript code.
These interfaces are documented here:
Mozilla Debugging Tips
[edit | edit source]Here are some suggestions for people that are debugging XForms:
Mozilla XForms Troubleshooting page
Testing Submissions
[edit | edit source]Sometimes when you are creating complex submissions to web services you need to make sure that what the XForms application is generating is exactly what the web service is expecting. Sometimes a web service vendor will provide a sample web forms client that correctly calls their service but the documentation on calling that service is somewhat lacking. One solution to this problem it to watch the HTTP packets leave the working application and compare them with the HTTP packets with your XForms. This can be done using an HTTP proxy tools such as Charles which also runs as a Firefox extension.
The "network" tab of standard web development debuggers, like Firebug and Google Chrome Javascript Console can be used to watch incoming and outgoing network traffic to and from the browser, allowing you to verify that the content of submissions, their methods, and HTTP error codes are what would be expected.
Using an HTTP Proxy With Firefox
[edit | edit source]A Proxy is a tools that "stands in" for a web server. It puts itself in between your web browser and the server and tells you what the browser just sent to the web server. To do this you have to set your web browser to use the proxy (by telling it to forward everything to another IP address) and the proxy then forwards it to the service.
When you are finished using the proxy, make sure you remember to disable the proxy by going to the Firefox Tools/Options/General/Connection Settings and click the Direction Connection to the Internet. If you do not your web browser will no longer function when Charles or Tamper Data shuts down.
Debugging WebDAV and Subversion
[edit | edit source]There are some XForms that are designed to use HTTP put, HTTP post and [w:WebDAV:WebDAV]. The WebDAV allows you to store not just the first version of a form but go back and see prior versions. Subversion FAQ [16] suggests you run the Wireshark packet sniffer and look at the data in the HTTP messages.
Verifiying that a file is well-formed
[edit | edit source]To verify that a data file is well formed, you can use the RUWF (Are you well-formed)? The XML Syntax Checker
Setting Mime-type in Internet Explorer Version 6.0
[edit | edit source]Some versions of IE 6.0 do not have the correct mime-type set for IE6. TO fix this you must add an entry to the Microsoft Windows Registry:
Open the Command Shell Enter the command "regedit"
[HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/xhtml+xml] "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" "Encoding"=hex:08,00,00,00 "Extension"=".xhtml"
Discussion
[edit | edit source]
Best practice
This cookbook identifies example programs that demonstrate best practices. An XForms Best Practice is a specific way of solving a general problem that has been selected from among posible solutions by various authors. There are a variety of reasons for best practices but in general best practices increase program modularity, maintainability and flexibility.
The following logo will appear next to sample programs that constitute a best practice: .
These should also be some reason in each example why this solution is usually preferred by developers over other solutions as well as give some indication of why this may not be appropriate in some situations.
Although a best practice is usually the preferred way of solving a given problem, it is not always the right choice for all circumstances. For example developers frequently put a style sheet in an external file but if you are doing training and want the example to contain the CSS file, there are good reasons to put the CSS file directly in the html header.
References
The following are some references to XForms
- Wikipedia XForms page
- Go to IBM Alphaworks and then try: demo/flash/display/cxde3 IBM GUI Demo
- Here is a nice intro from the IBM developer works. The Wikibook spam filter does not allow the direct link so you will have to put in the link to the IBM developer works web site and add "xml/library/x-xformsintro1/?ca=dnw-732"
Debugging Tips
If you are a newcomer to XForms and you are having problems debugging XForms you are not alone. XForms debugging can be tricky especially for newcomers. If you follow the newsgroups on XForms you will see several problems come up frequently.
Common Problems
[edit | edit source]These problems, roughly sorted in terms of frequency include the following:
- Make sure to name your files with the
.xhtml
extension. Many browsers including FireFox do not look for XML tags in files with the .htm or .html extension. - Problems related to forgetting to associate instance data with a namespace or the default namespace. This can be fixed by adding the
xmlns=""
parameter to your instance variable - Incorrect or missing namespaces in the body of a document. For example, if the default namespace is html the tag <input> is valid but the browser will look at it as <html:input> not <xf:input>. This happens frequently when users copy XForms example code from places that use XForms as the default namespace. This is a good reason that tutorial and training developers should not use XForms as the default namespace.
- Incorrect binding between the model and the view. This usually occurs because the "ref" or "nodeset" attributes are not correctly defined or that the group or repeat changes the path prefix of a data element.
- Failure to bind to the form to the instance because the XForms processor cannot find one or more instance specific namespaces. If you have customised your XForm with an XSLT or an XQuery before streaming it to your user, the processor might relegated the declaration of some of your namespaces to the instance where they first occur because it treats the contents of the ref and bind attributes on your xform as just content. However, your XForms processor probably expects the definition of the namespaces in your ref attributes to be on the parent axis and may not look in the model instances for any declarations. When this happens you will need to manually construct the root xhtml:html node, explicitly declaring any namespaces that appear in your form.
Using an XForms Validator
[edit | edit source]Some people have found this XForms validator helpful:
http://xformsinstitute.com/validator
This program will find common errors in XForms examples.
Using Eclipse to validate XPath
[edit | edit source]There is a nice eclipse plugin for XSLT providing also an XPath validation "view". See: http://wiki.eclipse.org/XSLT_Project
Debugging Tools for Firefox
[edit | edit source]One of the most useful Firefox extensions is the XForms Buddy debugger. This tool allows you to visually inspect all of the instances in the model while the XForms are running in the Firefox browser. This is especially useful for ensuring that instance values that are dynamically configured are correctly set by the XForms. The link to the site is: here
Printing your Bindings Using JavaScript
[edit | edit source]There is also a way to visually view your binding from within your JavaScript code.
These interfaces are documented here:
Mozilla Debugging Tips
[edit | edit source]Here are some suggestions for people that are debugging XForms:
Mozilla XForms Troubleshooting page
Testing Submissions
[edit | edit source]Sometimes when you are creating complex submissions to web services you need to make sure that what the XForms application is generating is exactly what the web service is expecting. Sometimes a web service vendor will provide a sample web forms client that correctly calls their service but the documentation on calling that service is somewhat lacking. One solution to this problem it to watch the HTTP packets leave the working application and compare them with the HTTP packets with your XForms. This can be done using an HTTP proxy tools such as Charles which also runs as a Firefox extension.
The "network" tab of standard web development debuggers, like Firebug and Google Chrome Javascript Console can be used to watch incoming and outgoing network traffic to and from the browser, allowing you to verify that the content of submissions, their methods, and HTTP error codes are what would be expected.
Using an HTTP Proxy With Firefox
[edit | edit source]A Proxy is a tools that "stands in" for a web server. It puts itself in between your web browser and the server and tells you what the browser just sent to the web server. To do this you have to set your web browser to use the proxy (by telling it to forward everything to another IP address) and the proxy then forwards it to the service.
When you are finished using the proxy, make sure you remember to disable the proxy by going to the Firefox Tools/Options/General/Connection Settings and click the Direction Connection to the Internet. If you do not your web browser will no longer function when Charles or Tamper Data shuts down.
Debugging WebDAV and Subversion
[edit | edit source]There are some XForms that are designed to use HTTP put, HTTP post and [w:WebDAV:WebDAV]. The WebDAV allows you to store not just the first version of a form but go back and see prior versions. Subversion FAQ [17] suggests you run the Wireshark packet sniffer and look at the data in the HTTP messages.
Verifiying that a file is well-formed
[edit | edit source]To verify that a data file is well formed, you can use the RUWF (Are you well-formed)? The XML Syntax Checker
Setting Mime-type in Internet Explorer Version 6.0
[edit | edit source]Some versions of IE 6.0 do not have the correct mime-type set for IE6. TO fix this you must add an entry to the Microsoft Windows Registry:
Open the Command Shell Enter the command "regedit"
[HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/xhtml+xml] "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" "Encoding"=hex:08,00,00,00 "Extension"=".xhtml"
Discussion
[edit | edit source]