pub struct Form<T> { /* private fields */ }Expand description
The values of a form, the values it started from, and what the visitor has done to it.
Put one in the page’s signal struct as a field of type Form<T>, where
T is a Signals struct of the form’s values that implements
Validate. The methods on Sig<S, Form<T>> then read and change it:
field binds a control, error gives the
message to show under it, form checks the rules before
calling an action, and reset puts the starting values back.
A form is dirty while its values differ from the values it started
from. A Sig::patch of one field from the server changes the value
and leaves the starting values alone, so the form stays dirty. A handler
that has saved the values patches the whole form with
Form::new(saved), which makes the saved values the new starting
values and clears what the visitor has done.
use hypersig::html::{button, input};
use hypersig::{Action, Form, Page, Rules, Sig, Signals, Validate};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize, Clone)]
struct Signup {
email: String,
}
impl Validate for Signup {
fn rules<S>(form: Sig<S, Self>, rules: &mut Rules<S, Self>) {
let email = form.at(Signup::email());
rules.check(Signup::email(), email.contains("@"), "Enter an email address.");
}
}
#[derive(Signals, Serialize, Deserialize)]
struct Join {
signup: Form<Signup>,
}
const JOIN: Action<Join, Signup> = Action::post("/join");
let signup = Join::signup();
let email = Signup::email();
let page = Page::new("Join", Join { signup: Form::new(Signup { email: String::new() }) })
.child(
signup
.form(JOIN.call_with(signup.value()))
.child(input().bind(signup.field(email)).on_blur(signup.touch(email)))
.child(button().attr("type", "submit").text("Join")),
);
assert!(page.render().contains("signup.touched.email"));Implementations§
Source§impl<T: Validate> Form<T>
impl<T: Validate> Form<T>
Sourcepub fn validate(value: &T) -> Result<(), FieldErrors<T>>
pub fn validate(value: &T) -> Result<(), FieldErrors<T>>
Checks value against the rules of T on the server.
The rules are the ones the browser checks, evaluated by the same evaluator that writes the first HTML, so a value the browser accepted passes here too. Call it in the action handler, because a request can come from something other than the page.
The exception is a rule the server cannot evaluate for the value it
received: arithmetic whose result is not finite, such as a division by
zero, or a date outside the years 1000 to 9999. That rule fails here,
with an empty message where its message cannot be evaluated either,
though the browser may have accepted the value. A value holding an
infinite or NaN number, which an HTML form’s inf or NaN parses to,
fails every rule.
§Errors
Returns the message of the first failing rule of each field.
§Panics
Panics if a rule reads Expr::now or Expr::random_below, which
only the browser can evaluate, or if value fails to serialize.
use hypersig::{Form, Rules, Sig, Signals, Validate};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
struct Signup {
email: String,
}
impl Validate for Signup {
fn rules<S>(form: Sig<S, Self>, rules: &mut Rules<S, Self>) {
let email = form.at(Signup::email());
rules.check(Signup::email(), email.contains("@"), "Enter an email address.");
}
}
let errors = Form::validate(&Signup { email: "ada".to_owned() }).unwrap_err();
assert_eq!(errors.message(Signup::email()), Some("Enter an email address."));
assert!(Form::validate(&Signup { email: "ada@example.com".to_owned() }).is_ok());