feat(StatusInput): add support for asynchronous validators
This adds support for asynchronous validators which are also just `StatusValidator`. There are a few differences to syncronous validators though: 1. `validate` function doesn't return, it's only used to trigger the async validation. Ideally it would return an async object like Promise or Observable but since we have to rely on QML `Connections`, this won't work. 2. As mentioned, `Connections` are needed to listen to async events so the validation can be resolved. 3. Validation has to be resolved by calling `input.updateValidity` inside the validator. That API notifies `StatusInput` that validation is has been performed and expects the name of the validator as well as either a boolean (true), if validation was successful, or, if validation has failed, a boolean (false) or an error object. Here's a `StatusENSValidator` as an example: ```qml StatusValidator { id: root name: "ensValidator" errorMessage: "Couldn't resolve ENS name." readonly property string uuid: Utils.uuid() property int debounceTime: 600 signal ensResolved(string address) validate: Backpressure.debounce(root, root.debounceTime, function (name) { name = name.startsWith("@") ? name.substring(1) : name walletModel.ensView.resolveENS(name, uuid) }) Connections { target: walletModel.ensView onEnsWasResolved: { if (uuid !== root.uuid) { return } root.ensResolved(resolvedAddress) input.updateValidityAndPendingState(root.name, resolvedAddress !== "") } } } ``` Closes #395
This commit is contained in:
parent
899f4461bb
commit
fe67997696
|
@ -47,6 +47,7 @@ Item {
|
|||
property bool valid: true
|
||||
property bool pristine: true
|
||||
property bool dirty: false
|
||||
property bool pending: false
|
||||
property bool leftIcon: true
|
||||
|
||||
property StatusIconSettings icon: StatusIconSettings {
|
||||
|
|
|
@ -24,6 +24,7 @@ Item {
|
|||
|
||||
property alias input: statusBaseInput
|
||||
property alias valid: statusBaseInput.valid
|
||||
property alias pending: statusBaseInput.pending
|
||||
property alias text: statusBaseInput.text
|
||||
property string label: ""
|
||||
property string secondaryLabel: ""
|
||||
|
@ -32,13 +33,18 @@ Item {
|
|||
property real leftPadding: 16
|
||||
property real rightPadding: 16
|
||||
property list<StatusValidator> validators
|
||||
property list<StatusValidator> asyncValidators
|
||||
property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty
|
||||
|
||||
property var pendingValidators: []
|
||||
|
||||
enum ValidationMode {
|
||||
OnlyWhenDirty, // validates input only after it has become dirty
|
||||
Always // validates input even before it has become dirty
|
||||
}
|
||||
|
||||
property var errors: ({})
|
||||
property var asyncErrors: ({})
|
||||
|
||||
function reset() {
|
||||
statusBaseInput.valid = false
|
||||
|
@ -78,6 +84,40 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (asyncValidators.length && !Object.values(errors).length) {
|
||||
root.pending = true
|
||||
for (let idx in asyncValidators) {
|
||||
let asyncValidator = asyncValidators[idx]
|
||||
if (pendingValidators.indexOf(asyncValidator.name) == -1) {
|
||||
asyncValidator.input = root
|
||||
pendingValidators.push(asyncValidator.name)
|
||||
asyncValidator.validate(statusBaseInput.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateValidity(validatorName, result) {
|
||||
if (!asyncErrors) {
|
||||
asyncErrors = {}
|
||||
}
|
||||
|
||||
if (typeof result === "boolean" && result) {
|
||||
if (asyncErrors[validatorName] !== undefined) {
|
||||
delete asyncErrors[validatorName]
|
||||
}
|
||||
errorMessage.text = ""
|
||||
} else {
|
||||
asyncErrors[validatorName] = result
|
||||
for (let idx in asyncValidators) {
|
||||
errorMessage.text = asyncValidators[idx].errorMessage || root.errorMessage
|
||||
break;
|
||||
}
|
||||
}
|
||||
pendingValidators = pendingValidators.filter(v => v !== validatorName)
|
||||
root.pending = pendingValidators.length > 0
|
||||
root.valid = Object.values(asyncErrors).length == 0
|
||||
}
|
||||
|
||||
Component.onCompleted: validate()
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import QtQuick 2.13
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
QtObject {
|
||||
id: statusValidator
|
||||
|
||||
property string name: ""
|
||||
property string errorMessage: "invalid input"
|
||||
property StatusInput input
|
||||
|
||||
property var validate: function (value) {
|
||||
return true
|
||||
|
|
Loading…
Reference in New Issue