|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 data
save: save data via the persistence layer
success-message: show a success message
error-message: show an error message
send: send the data to an HTTP service
summary: navigate to these Form Runner pages
navigate: navigate to an external page
visit-all: mark all controls as visited
unvisit-all: mark all controls as not visited
expand-all: expand all sections
collapse-all: collapse all sections
result-dialog: show the result dialog
captcha: trigger the captcha
success: complete the process
process: 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
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,
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)
And we introduce new buttons with predefined behavior:
save-final: validate and save to the db
save-draft: save to the db without validating
send: 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 (
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
We hope this shows a little bit what’s now possible! This feature will be available in Orbeon Forms 4.2.