Open avernet opened 10 years ago
This comment contains ideas moved from the wiki.
Currently, Form Runner only supports "internal" validation, that is validation expressed with types and constraints (like in plain XForms).
Often, you need external validation, which might involve complex calculations or lookups that are hard or inconvenient to implement with XForms. E.g.:
A possible way of implementing this is documented in this how-to: Perform external validation.
This works in limited cases but has limitations, including:
These limitations are likely not acceptable for Form Runner as we want this feature to be future-proof.
With internal validation, data is frequently revalidated, typically whenever a field changes.
With external validation, this by default might be too costly. In that case, external validation:
Validation information is provided by a service:
The exact format of the response is TBD, but could be:
In XForms, Model Item Properties (MIPs) are declarative, so don't need to be "persisted" in an instance DOM as they can be recomputed as needed.
With external validation, we might need to introduce a type of persistent, imperative MIPs, settable with an action:
<xxf:setmip ref="foo/bar" name="valid" value="false()"/>
and readable as an XPath function:
xxf:getmip($name as xs:string) as item()
An action to clear all MIPs, or all MIPs of a given type, might be needed:
<xxf:clearmip ref="instance()" name="valid"/>
NOTE: Persistent MIPs do not replace declarative MIPs: they combine with them.
When nodes are removed from an instance, these MIPs are automatically removed.
This has the following impact on the implementation:
None for now, this has to be configured through properties.
At this point, I am not 100% sure that the "persistent MIP idea" is the best one. But the idea that external validation could be triggered by default only upon save/submit is good, and maybe configurable via independent properties or directly in the save/send processes properties.
There should probably also be ways to trigger external validation separately, maybe by adding an action once we have separated Form Builder actions from services.
As a first step, it might be ok to say the following:
Comment on the proposal above: we could send the whole XForms instance, or possibly pass a list of control names to send. Then only those values would be sent, as URL parameters or in a application/x-www-form-urlencoded
POST.
Clearly an important step is to determine the format(s) of the request/response.
With datasets, the workaround can look like:
This is still heavy but doesn't require hidden controls. A single service call can return all validity information.
Two scenarios to consider:
Both are probably reasonsable depending on the situation.
With datasets:
Example:
<xf:bind
ref="instance('fr-form-instance')//*[empty(*)]"
constraint="
for $name in name(.), $ds in fr:dataset('validation-dataset') return
empty($ds/*[name() = $name][1]/[@valid = 'false'])
"
/>
Above assuming a validation document like:
<validation>
<name valid="false"/>
<foo valid="false"/>
<bar valid="false"/>
</validation
You can vary the format of the validation document.
The above might work if we add the ability to set a dataset with the result of a process send()
action.
Right now this is possible, but only indirectly:
false()
.This approach has some limitations: