Wiki

Clone wiki

javarosa / PreloadHandlersRedux

Re-thinking Preload Handlers

I've often felt that JavaRosa custom preload handlers are a very specific case of a more general need -- dynamically setting the answers to questions (hidden or otherwise) based on some computation or lookup. And xforms provides ways of doing the latter. So I think we should strive to replace our custom preload handler tags with these xforms-sanctioned methods.

It's not that easy, though, as:

  • preload handlers in their current form do more than just their name suggests: they can also indicate specific post-processing actions
  • the xforms syntax might not be as clean or intuitive as the preload handler

Use cases

1. Setting the answer to a question as a result of a computation/lookup, and this answer is not meant to be edited, or even seen, by the user (though it may be shown to the user read-only). This includes: a. computed fields that depend on questions answered in the form (e.g., a complex calculation to determine a 'risk factor', and we want to store this result explicitly in the instance) b. static meta-data fields, such as device ID, patient info, start/end time. This becomes more complicated, as most should be calculated at form load, but some (end time) should be done at form completion

2. Setting the default answer to a question as a result of a computation/lookup, but this answer may then be changed by the user. For example, 'default district' taken from a property on the phone.

3. Post-processing certain fields: writing 'use-last-entered-as-default-next-time' values back to their associated property, storing patient-linked info back into a patient record, etc.

Each of these situations might require slightly different syntax.

Initial thoughts

All calculated/looked-up values are produced by xpath expressions. XPath hooks will be provided to link to external data and fill the role of our current preload handlers.

'''(1a)''' might best be done via the calculate property of a <bind>

<bind nodeset="high-risk" calculate="risk-factor(../num_past_pregnancies, ../past_complications, ../age)" />

'''(1b)''' depends on the nature of the data:

  • static data that doesn't change based on when you evaluate it (basically everything)

can also be handled via the calculate property

<bind nodeset="meta/device-id" calculate="fetch-property('DeviceID')" />
  • dynamic data that changes based on when you evaluate it (pretty much timestamps only)

likely a <setvalue> tag triggered by the appropriate xform-ready and xform-model-destruct xforms events (for 'set-on-form-load' and 'set-on-form-done', respectively). The 'set-on-form-load' could also be handled via calculate, since the semantics dictate it should be calculated upon initialization. But for consistency, both cases should probably use the same construct (having time-start and time-end being set in different ways is ugly). This might look something like this:

<model>
  <instance>
    <meta>
      <time-start />
      <time-end />
      ...
    </meta>
    ...
  </instance>

  <!-- <bind>s here -->

  <action ev:event="xform-ready"><setvalue bind="meta/time-start" value="now()" /></action> 
  <action ev:event="xform-model-destruct"><setvalue bind="meta/time-end" value="now()" /></action>
</model>

I'm also wary of going down the rabbit hole of making a general-purpose XML event handler. I also think we'll have to take some liberty with what some events mean and when exactly they should be applied, in order to maintain usefulness.

'''(2)''' would need to use <setvalue>, as the value from a calculate would get wiped out ('recalculated') each time it was changed

'''(3)''' very unsure what to do about this

Updated