Open ebruchez opened 7 years ago
With what we have now, one way of doing this is to have the component maintain a valid
attribute on the bound element, and contribute a constraint="@valid = 'true'"
to the xf:bind
in the form. One benefit of this approach is that it is the component itself that becomes invalid, rather than a control inside the component, so we can safely rely on the lhha
XBL mode, and the user can add its own validation. However, amongst the downside of this technique, it doesn't allow for the component to supply its own alert message, per RFE #3300.
The validating.xbl
, to be deployed in xbl/example/validating
, and a reference to that file added to, say, the oxf.fb.toolbox.group.example.uri.*.*
property, is an example of this technique.
For reference, as a general principle, we would like to keep the unidirectional data flow from model to view. The view communicates changes to the model using events or data binding (which could be seen as dispatching a special event). Having a bind
in the view modifying MIPs in the model is therefore not acceptable, unless the MIPs are set using events.
Getting back to this from customer with components such as:
Some can get away with a simple regex, but some need a more elaborate algorithm to perform the validation.
Conceptually, validation is a function.
Let's remember that, right now, form validation is done via the error summary and is based on the validity of the controls (via xforms-valid
/xforms-invalid
). But most controls become valid/invalid via constraints in the model.
Now, given this, we are really close by having components:
xf:bind
What we are missing here is:
Do we care about the XBL component itself being valid/invalid? It seems like it because we had issues with the LHHA mode and seeing duplicate errors in the Error Summary. In addition, conceptually, unlike with section templates, it is the component that is valid/invalid.
Alternatively, we could find a way to export a validation function from the component so that it would apply at the top-level model.
Assuming the following:
binding value lhha
modesCould we implement logic whereby the validity of the XBL component would be impacted by the validity of the mirrored element? In other words, we wouldn't propagate the MIP to the main model, but we would have the external binding AND the internal one contribute to the validity of the control.
Another angle is the datatype. Right now, we have datatypes for numbers, for example. But we don't have datatypes for "US SSN", "UK phone number", etc. Should we move more towards a pluggable system of datatypes?
fr:component-param-value()
.Say we have this. Then a "US SSN" component could simply have for example a type="fr:us-ssn"
in its data template, and bind to xxf-type('fr:us-ssn')
values. Formatting could be, in a first step, done by the component, like what we do for fr:number
.
How would we plug such datatypes?
Concretely, what would the last comment entail?
<constraints>
section to the XBL binding.This would not be visible to Form Builder, so the user cannot change those built-in constraints for a datatype. The user can add other custom constraints as usual.
Q: What would happen if multiple components define <constraints>
for the same datatype?
A: They could be merged (AND logic), or we could take the first one only, or the last one, or cause an error. It probably should be avoided. Either a different datatype should be used, or one of the bindings should be removed.
Would this take us in the right direction?
Would we still benefit from implementing the "internal mirror instance validation impacts the component validity" part?
Suggestions for a <constraints>
section:
<xxbl:constraints>
<xf:constraint value="...">
<xf:alert lang="en">My custom error message</xf:alert>
<xf:alert lang="fr">Mon message d'erreur spécifique</xf:alert>
</xf:constraint>
<xf:constraint level="warning" value="xxf:max-length(42)">
<xf:alert lang="en">My custom warning message</xf:alert>
<xf:alert lang="fr">Mon message d'attention spécifique</xf:alert>
</xf:constraint>
</xxbl:constraints>
<xbl:template>
....
We don't have to support the nested alerts at first and that could be part of #3300.
Following discussion with @avernet:
<xxf:setvalid>
action.
So my question is how all this intersects.
Point 1 above seems orthogonal.
Point 2 is partly a shortcut to defining:
So I think we could go ahead with this idea of datatype and constraints mapped via XBL.
Say a form has an <xf:bind type="fr:us-ssn"/>
.
This translates semantically into:
<xf:bind type="fr:us-ssn">
<xf:constraint value="...">
<xf:alert lang="en">My custom error message</xf:alert>
<xf:alert lang="fr">Mon message d'erreur spécifique</xf:alert>
</xf:constraint>
<xf:constraint level="warning" value="xxf:max-length(42)">
<xf:alert lang="en">My custom warning message</xf:alert>
<xf:alert lang="fr">Mon message d'attention spécifique</xf:alert>
</xf:constraint>
</xf:bind>
Now, from an implementation perspective:
Model.bindTree
, do we have already access to the XBL components in the XBL library? The annotator should already have called initializeBindingLibraryIfNeeded()
so yes, and even if no, we can call it when we need it. So I would say this is ok.StaticBind
refers to an Element
but it seems only to find attributes and nested elements. We could create this pointing to the element in the AbstractBinding
, probably.If the above holds, then it should be pretty eas to do.
We've had multiple use cases for XBL components which must validate their data from the inside. That is, those components have the knowledge of how the data they read and write should be validated. We don't have a good system for that.
Options we have considered:
xforms-valid
/xforms-invalid
See also #1193.