Goal: a login/signup field that validates synchronously (non-empty, length, format) and also runs an asynchronous rule (e.g. "username
available?") without blocking the UI.
See also: docs/guide/validation.md, docs/reference/error-model.md, and the validation contract V-N in the headers.
Synchronous rules
FormValidator::rule(predicate, message, rule_id) attaches a predicate that runs on every change of the bound Property. A failing rule surfaces its message under the given rule_id.
aria::FormValidator form;
form.rule([&]{
return !username.
get().empty(); },
"Username is required", "required");
form.rule([&]{
return username.
get().size() >= 3; },
"At least 3 characters", "min_len");
auto sub = form.is_valid.
on_changed([](
bool ok){ submit_button.enabled = ok; });
Definition property.hpp:103
T get() const
Auto-tracked read.
Definition property.hpp:138
::aria::Subscription on_changed(std::function< void(const T &)> fn)
Run fn(new_value) every time the value changes.
Definition property.hpp:200
Asynchronous rule
aria::async::AsyncValidator<T> runs a coroutine rule on a worker executor and writes the pending/valid/invalid state back on the UI executor. Its factory has the signature std::function<Task<AsyncRuleResult>(T value, CancellationToken tok)> (see aria/async/async_validator.hpp for AsyncRuleResult). It attaches to a sync aria::Validator<T> plus its source aria::Property<T>:
ui_executor, net_pool,
[](std::string name, aria::CancellationToken tok)
co_return co_await api::check_username_free(std::move(name), tok);
}};
auto async_sub = uniqueness.
attach_to(username_validator, username);
Definition validator.hpp:135
Driver that turns a coroutine factory into a latest-wins async validation rule attached to a Validato...
Definition async_validator.hpp:210
::aria::Subscription attach_to(::aria::Validator< T > &v, ::aria::Property< T > &source)
Attach to a Validator + its source Property.
Definition async_validator.hpp:237
Why this is safe
- No torn state. The async rule cancels the previous in-flight run on every new keystroke and mints a fresh CancellationSource (V-1), so a slow earlier request can never overwrite a newer result.
- Pending is observable. attach_to immediately fires begin_pending() (V-2), so the UI can show a spinner while the network rule resolves.
- Lifetime is RAII. Destroying the returned Subscription cancels the in-flight rule and detaches (V-6) — no callback fires against a dead form.