![]() |
Photo by Keoni Cabral |
Up to version 4.1, Orbeon Forms had a few configurable buttons to specify what happens with form data:
- The “Save” button saves data to the database.
- The “Submit” button saves data and shows a dialog after saving (with options to clear data, keep data, navigate to another page, or close the window).
- The “Send” (AKA “workflow-send”) button saves the data and then allows:
- sending an email
- sending form data to a service
- redirecting the user to a success or error page
The reason these specific buttons came to be is mostly historical: as more functionality was needed over time, more buttons were added with properties to configure them. The distinction between “Submit” and “Send” in particular is arbitrary!
Since recently we’ve been asked for more options, we used the opportunity to implement a much more flexible system.
First, let’s start by saying that we don’t want to implement a full-fledged workflow engine: that’s something other products do better than Orbeon Forms. Instead the idea is to be able to specify very simple sequential processes to execute when the user presses a button.
We started with specifying a list of reusable actions:
validate
: validate form datasave
: save data via the persistence layersuccess-message
: show a success messageerror-message
: show an error messagepdf
: create a PDF file from the dataemail
: send an emailsend
: send the data to an HTTP servicereview
,edit
,summary
: navigate to these Form Runner pagesnavigate
: navigate to an external pagevisit-all
: mark all controls as visitedunvisit-all
: mark all controls as not visitedexpand-all
: expand all sectionscollapse-all
: collapse all sectionsresult-dialog
: show the result dialogcaptcha
: trigger the captchasuccess
: complete the processprocess
: run a sub-process
Then we needed to:
- specify which of these actions to run and in which order
- decide what to do when they succeed or fail
- decide how to associate them with buttons
We came up with a very simple syntax which you place in configuration properties. For example, the good old “Save” button is specified this way:
require-valid
then save
then success-message("save-success")
recover error-message("database-error")
Notice that there are action names, like save
and success-message
(require-valid
itself is a sub-process which runs a number of steps and stops processing if the data is not valid), and two different combinators, then
and recover
. When an action succeeds, then
is used to specify what is the following action. When an action fails, recover
can be used to specify what action to do in that case.
So in the example above what you want to say is the following: start by validating the data, then in case of success save the data, and then if that’s successful show a success message. If saving has failed, then show an error message.
A process which just saves the data without checking validity and shows success and error messages looks like this:
save
then success-message("save-draft-success")
recover error-message("database-error")
Validating and sending data to a service looks like this:
require-valid
then send("oxf.fr.detail.send.success")
Some actions can take parameters. In the example above we point to properties to configure the send
action. This means that, within a single process, you can have any number of send
actions which send data to various services. This also allows you to have separate buttons to send data to different services. These two scenarios were not possible before.
We are keeping but deprecating these buttons:
save
(which uses a property to determine whether to validate or not)submit
workflow-send
And we introduce new buttons with predefined behavior:
save-final
: validate and save to the dbsave-draft
: save to the db without validatingsend
: validate and send to a service
In fact all buttons can do the same tasks if they are configured appropriately! But by default the buttons above are preconfigured to do different tasks, for convenience.
So how do you can figure things? Say you want to specify a couple of buttons on your “acme/hr” form. Like before, you define a property:
<property
as="xs:string"
name="oxf.fr.detail.buttons.acme.hr"
value="save-draft send"/>
This places “Save” and “Send” buttons on the page. Each button is automatically associated with processes of the same names (save-draft
and send
). These particular buttons and process names are standard, but we can override them specifically for our form. Again, this is done with a property:
<property
as="xs:string"
name="oxf.fr.detail.process.send.acme.hr"
value='require-valid
then pdf
then email
then send("http://example.org/")
then navigate("/success")
recover navigate("/failure")'/>
Button labels can be overridden as well, as was the case before:
<property
as="xs:string"
name="oxf.fr.resource.*.*.en.detail.buttons.send"
value="Fancy Send"/>
All the configuration above for a button called send
could have been done with an entirely custom button named foo
.
We hope this shows a little bit what’s now possible! This feature will be available in Orbeon Forms 4.2.
No comments:
Post a Comment