What you'll be learning
The project this time is to improve on the delivery task workflow by only showing the driver the form that starts the workflow off. The forms that correspond to later stages of the workflow will only be accessible through this first one. This will make sure that the driver doesn't mix up the order of forms.
To make this happen, you'll first have to 'hide' everything but the kick-off form from the user on the one hand, and program the mobile client to open the next form in the sequence whenever the driver submits one of the workflow forms. Ultimately, you need to make sure that the workflow stays on the track outlined in the diagram below.
The light blue forms are hidden in the client, and the arrows represent the
automatically opening new form when a form is submitted. As you can see, the Load
cargo form still includes an option to cancel a delivery and start over.
The workflow scripts that process the forms will naturally also need a bit of tweaking to accommodate for the changes in the new versions.
Finally, you'll update the start of the workflow to make it a bit more informative and user-friendly by laying it out as a table.
There's a lot to dom so let's get to work.
Hide forms in the mobile client
This one is actually ridiculously easy: just make a form's menuOrder
attribute hidden
, and hey presto, it's all gone. The root element of
the load
form, for example, should look like
this:
Hide
the deliver
form as well, leaving confirm
alone for now,
and save and publish as usual. If you'd open the Mobilengine client now, which is not
recommended, you'll just see Pick your next delivery in the sidebar,
without any way to advance in the workflow. Nice job breaking it. Time to fix the thing.
Make any button submit or discard a form
You were promised an automatically opening new form whenever you submit one. Here it is:
the submitbutton
and discardbutton
controls, apart from
doing what their names say (submitting or discarding the form), also have a
nextForm
property. Make it equal to the id
of any other
form in the given solution, and it will magically open up in the client when the user taps
the button.
Are you beginning to see the possibilities here? Have a submitbutton
in
confirm
point to load
, and one in load
point to deliver
, and you've got an automated workflow, right? Indeed you
do, but you'll also need to deactivate the burnt-in default Submit
and X buttons so that the user will have no choice but to use your
new pre-programmed buttons.
The header
element represents the header bar of your form, and accepts up to
one submitbutton
and discardbutton
controls. If you
include a header
but leave it empty, the form will have no header bar.
Observe.
<form id='confirm' menuName='Pick your next delivery' platforms='ios' xmlns='http://schemas.mobilengine.com/fls/v2' menuOrder='1'><header></header>
<dropdown id='tasks' label='Select a delivery based on loading address: ' choices='{SELECT a.usr, a.assignment_id, a.load_address, a.status FROM assignments a WHERE a.usr==sysp.user AND a.status=="Assigned"}' keyMap='{assignment_id}' textMap='{load_address}'/> <linkview label='Get directions to loading address' text='{tasks.selectedText}' url='{SELECT "http://maps.apple.com/?address=" || REPLACE(tasks.selectedText, " ", "%20") address}'/> <submitbutton id='submit' text='Confirm the selected delivery' nextForm='{forms.load}'/>
</form>
As
you've no doubt noticed, this code does away with the otherwise elegant if
wrapper for the content. No need: the user will now be prodded through the workflow, and
won't be able to get back to the confirm
form unless the delivery task is
completed.
Save the new version, and publish to see what this headerless, custom-submit-button form looks like.
Figure 116. Notice the lack of Submit and X buttons in the header. The Confirm the selected delivery button submits the form.
Awesome. Let's revamp the other forms as well.
In load.fls.xml
there need to be two submitbutton
s
because you want to let the user abort the delivery at this point, which means shifting the
status of the in-progress task to Cancelled
. You don't need to worry about
actually doing this yet; the workflow script is responsible for all necessary
status-shifting.
And the published form looks thusly:
The same pattern is repeated for
deliver
:
The form won't look like much before its processing script is updated- the screenshot below is what the published form will look like with a script tweak that you'll make in a moment.
As the overview diagram suggests, the submitbutton
in this last stage
of the workflow should shift the driver back to the beginning of the delivery task routine.
When the Pick your next delivery form is automatically opened,
there'll be one fewer delivery task to choose from, until at the end of the day or shift,
all the deliveries will have been moved to status="Completed"
. For that to
happen, though, the workflow scripts should also be doing their job.
Check the workflow scripts to match the changes
Let's review what needs to change in the scripts to keep the workflow from breaking.
You didn't touch the dropdown
whose selectedKey
property
confirmer
uses to identify the record to
reftab.Update()
.
And there was no change to the confirmed
and loaded
variables that loader
and unloader
use, so they should
continue to be working just fine.
Better safe than sorry though: Save all the new forms and publish with the reference table. The workflow should work as advertised.
Crank up the user experience
The workflow kickoff-form, that your driver will look at the most, isn't very appealing: the user needs to tap into the dropdown
to
see the options, and they don't get any info about the task apart from the loading address.
You can change that by including the driver's tasks for the day in a table that displays a
bit more detail, and that the driver can just scan at a glance. Maybe include the name of
the client and the date that the driver needs to load the goods by.
There's nothing new in the form below, as you'll see; the layout is pimped up ad it takes a
page from the load
and unload
playbook by inserting a
variable to hold the assignment_id
of each displayed record from
assignments
. This is of course for the sole benefit of the workflow
script to identify the row to be
updated.
<form id='confirm'...> <header></header> <table id='assigned' record='a' recordset='{SELECT a.usr, a.assignment_id, a.load_address, a.client, a.load_date, a.status FROM assignments a WHERE a.usr==sysp.user AND a.status=="Assigned"}' > <header> <row> <cell> <textview text='Client'/> </cell> <cell> <textview text='Load date'/> </cell> <cell> <textview text='Load address'/> </cell> <cell> <textview text='Client'/> </cell> </row> </header> <row> <declarations> <let id='id' shape='scalar' value='{a.assignment_id}'/> </declarations> <cell> <textview text='{a.client}'/> </cell> <cell> <textview text='{FORMATDTL(a.load_date, (dtf yyyy"/"MM"/"dd))}'/> </cell> <cell> <linkview text='{a.load_address}' url='{SELECT "http://maps.apple.com/?address=" || REPLACE(a.load_address, " ", "%20") address}'/> </cell> <cell> <submitbutton id='confirmer' text='Confirm delivery' nextForm='{forms.load}'/> </cell> </row> </table> </form>
Save,
publish, and open. Ladies and gentlemen, meet the tabular confirm
form.
Needless to say, the confirm
workflow script, which we've renamed
accepter
to represent the change, also needs to be updated. Your
submitbutton
is now inside a table
, so you'd need to
iterate through it row by row, but you've decided to take a different route, and exploit the
form's submitButton
read-only property. It gives you a reference in the workflow script to whichever button was
used to submit the form, and all you need to do is crawl up and down the XML tree using the
parentControl
property to find the values your script needs for the
Update()
.
You
might have noticed that the parentControl
of the
submitButton
seems to skip the containing cell
and
head straight for the row
control. This is how
submitbutton
s inside cell
s work.
You're ladling on the awesome thick and fast. The Jedi mind-trick you'll learn in the next section will make your clients want to add a digit to your salary.