pub struct TextField<F = ()>(/* private fields */);Expand description
A text field: Field::text, or a record form’s text control (F is the form).
Implementations§
Source§impl<F> TextField<F>
impl<F> TextField<F>
Sourcepub fn gt(self, other: &TextField<F>) -> Self
pub fn gt(self, other: &TextField<F>) -> Self
Refuse a value not above other’s, a field of the same form and type that orders: a
number, or a jiff date, time, date and time, or timestamp.
let starts = Field::text(lens!(Trip.starts_on));
let ends = Field::text(lens!(Trip.ends_on)).gte(&starts);
Schema::new((starts, ends));- Only the server checks it, in the same round as the controls’ other rules, and the error renders on this field, naming the other by its label.
- The other’s value is its posted one, else the one the record stores, as a field disabled on edit posts none. A blank value on either side, or another field a condition hides, skips the comparison: whether a value is required is the field’s type to say.
- An edit that changes neither field does not check them again, as a value the record already stores is not; changing either one does.
- An edit checks a repeater row’s comparisons again unless the row’s two fields keep the values the record stores at the same row position.
- A field of
Option<T>compares with one ofT. Mounting refuses the field itself, another field the schema does not place, one of another type or control, and a type without an order. A repeater’s row field compares with another field of the same row. - The refusal tells what the other field holds, so mounting also refuses one that a
FieldAccessviewrule hides from some user:FieldAccessFault::Watched.
Source§impl<F> TextField<F>
impl<F> TextField<F>
Sourcepub fn default(self, value: impl IntoFormValue) -> Self
pub fn default(self, value: impl IntoFormValue) -> Self
Fills the create form’s control with value: any
FormScalar or a &str in the form spelling, or, for a
multiple choice, an array or Vec of them. On a
disabled field it is the value a create stores. A schema
refuses a default the control never posts: one a typed field does not parse, one
not among a choice’s options, a list on a control posting one value, and one value
on a multiple choice.
Field::choice(Post::fields().status())
.options(["draft", "published"])
.default("draft");
Field::text(Post::fields().views()).default(0_i64).disabled();
Field::choice_input("channels")
.options(["email", "sms"])
.multiple()
.default(["email"]);- The control names its help text in
aria-describedby, beside its error. - A disabled control renders
disabled, so the browser posts nothing for it, and the panel drops a key posted anyway, with a file field’s carried upload. An edit keeps the stored value. A create stores the field’s default, else its blank answer:.disabled()on a field with neither refuses to mount, since no create could fill it. .disabled_on_edit()leaves the create form’s control enabled: the create sets the value, and no edit changes it.- A condition watching a disabled field reads what the browser shows: its default on a create, its stored value on an edit, never what the submission posts.
- A default seeds the create form and an action’s input form; an edit form shows the stored value. The blank answer is different: it is what an empty submission stores. Mounting refuses a default the control never posts: one a typed field does not parse, or not one of a choice’s options.
- A repeater’s row controls take neither
disablednordefault: mounting refuses both.
Source§impl<F> TextField<F>
impl<F> TextField<F>
pub fn label(self, label: impl Into<Text>) -> Self
pub fn name(&self) -> &str
Sourcepub fn visible_when(
self,
watched: &impl Watched<F>,
values: impl IntoIterator<Item = impl Into<String>>,
) -> Self
pub fn visible_when( self, watched: &impl Watched<F>, values: impl IntoIterator<Item = impl Into<String>>, ) -> Self
Shows the field only while watched posts one of values: an option’s value, or
true for a checked toggle. A hidden field posts nothing, so an edit keeps its
stored value and a create takes its blank answer; a field with no blank answer
cannot be conditional. A field shows under one condition: a later call replaces an
earlier one, so a field depending on two watched fields sits in a
Section guarded by the other.
let kind = Field::choice(Customer::fields().kind()).options(["person", "company"]);
let vat = Field::text(Customer::fields().vat_number()).visible_when(&kind, ["company"]);
Schema::new((kind, vat));- The browser shows and hides the field as the watched one changes, with no request. A hidden field’s control is disabled, so the browser neither validates nor posts it. Without JavaScript, the fields start as the stored values show them and stay that way.
- The panel reads a submission the same way and drops a hidden field’s posted key, and a file field’s carried upload: an edit keeps the stored value, and a create stores the blank answer. A conditional field therefore needs a blank answer, and mounting refuses one without.
- Mounting also refuses a value the watched field never posts (a choice’s option or
a toggle’s
trueandfalseare checked), and a condition watching a field that another condition hides while the guarded field still shows: place the guarded field inside the block that hides the watched one. A schema also refuses a condition watching a field it does not place, which only a page’s or an action’s schema can do: a resource’s form places every record-form field. - A toggle is followed through its checkbox. An app’s own checkbox
Controlposts the samevaluechecked or not, so a condition cannot follow it. - A multiple choice’s key holds a list, which no condition value spells: mounting refuses a condition watching one.
Source§impl<F> TextField<F>
impl<F> TextField<F>
Sourcepub fn help(self, text: impl Into<Text>) -> Self
pub fn help(self, text: impl Into<Text>) -> Self
Renders text under the control, which the control names as its description.
Sourcepub fn disabled(self) -> Self
pub fn disabled(self) -> Self
Renders the control disabled on the create and edit forms. The server drops a
value posted for it anyway, so an edit keeps the stored value and a create takes
the field’s default, else its blank answer; a field with neither cannot be
created, and its panel refuses to mount.
Sourcepub fn disabled_on_edit(self) -> Self
pub fn disabled_on_edit(self) -> Self
Renders the control disabled on the edit form only: the create form sets the value, and no edit changes it.
Sourcepub fn custom(self, control: impl Control + 'static) -> CustomField<F>
pub fn custom(self, control: impl Control + 'static) -> CustomField<F>
Renders the field with an app’s Control instead, as Field::custom does:
how a record form’s control takes a custom input. The field keeps its key and
label; the replaced control’s own modifiers, such as email, unique or
options, are dropped with it.
Source§impl<F> TextField<F>
impl<F> TextField<F>
Sourcepub fn choice(self) -> ChoiceField<F>
pub fn choice(self) -> ChoiceField<F>
Renders the field as a choice instead, as Field::choice does, ready for
options or relationship.
The replaced control’s own modifiers are dropped with it.
Source§impl<F> TextField<F>
impl<F> TextField<F>
Sourcepub fn rich_text(self) -> RichTextField<F>
pub fn rich_text(self) -> RichTextField<F>
Renders the field as a rich text editor instead, storing HTML. The
field’s type must be String or Option<String>, else mounting the panel fails, and the
text control’s own modifiers are dropped.
use tablo_core::Tool;
let c = PostForm::controls();
c.body
.rich_text()
.toolbar(&[&[Tool::Bold, Tool::Italic], &[Tool::BulletList]]);Sourcepub fn email(self) -> Self
pub fn email(self) -> Self
Validate the value as an email address, and render type="email": the domain needs two
labels (a@b is refused), a display name (Ada <ada@example.com>) is refused, and the
address is capped at 254 bytes.
Sourcepub fn url(self) -> Self
pub fn url(self) -> Self
Validate the value as an absolute http or https URL naming a host, and render
type="url". The browser’s own check takes any scheme, so the server refuses the others,
such as javascript:, which a link to the value would run.
Sourcepub fn tel(self) -> Self
pub fn tel(self) -> Self
Render type="tel", which brings up a phone keypad. No format is checked, since numbers
vary by country: add a pattern to require one.
Sourcepub fn password(self) -> Self
pub fn password(self) -> Self
Render type="password": the browser masks the value, a button beside it shows what was
typed, and a refused form renders the control empty rather than echoing the password back
into the page. It renders the one-line
input even when multiline.
Sourcepub fn unique(self) -> Self
pub fn unique(self) -> Self
Probes a unique index before the write, and reports a taken value inline. A text field over a column with a unique index probes without it; mounting refuses it on a column no unique index covers, and on a non-nullable column whose record-form field has a blank answer, since every empty submission would store one value.
The probe runs before the write, so two concurrent submissions can both pass it; the index stays the final check. When a write fails on a database error, the form probes again once the transaction is rolled back, so the losing submission re-renders with the same inline error, and a failure the probe does not explain answers 500. That needs the database to refuse the losing write once the winning one commits, as PostgreSQL and MySQL do; SQLite can refuse it as busy before then, and Turso’s concurrent transactions conflict at commit, so either can still answer 500. The probe reads through the resource’s scoped query, so an index broader than the scope, such as one wider than the tenancy, also answers 500.
Sourcepub fn placeholder(self, placeholder: impl Into<Text>) -> Self
pub fn placeholder(self, placeholder: impl Into<Text>) -> Self
The control’s placeholder text.
Sourcepub fn prefix(self, text: impl Into<Text>) -> Self
pub fn prefix(self, text: impl Into<Text>) -> Self
Text shown before the one-line input, joined to it, such as a currency: .prefix("$"). It
is not part of the value, and a multiline textarea renders none.
Sourcepub fn suffix(self, text: impl Into<Text>) -> Self
pub fn suffix(self, text: impl Into<Text>) -> Self
Text shown after the one-line input, joined to it, such as a unit: .suffix("kg"). Like a
prefix, it is not part of the value.
Sourcepub fn suggestions(
self,
values: impl IntoIterator<Item = impl Into<String>>,
) -> Self
pub fn suggestions( self, values: impl IntoIterator<Item = impl Into<String>>, ) -> Self
Values the one-line input suggests as the user types, through a <datalist>. The user may
still enter any other value: use a choice to restrict them. A
password suggests none.
Field::text(lens!(Product.weight)).suffix("kg");
Field::text(lens!(Product.brand)).suggestions(["Acme", "Globex", "Initech"]);Sourcepub fn multiline(self, rows: u32) -> Self
pub fn multiline(self, rows: u32) -> Self
Render a <textarea> of rows lines rather than a one-line input,
for a column holding prose.
Sourcepub fn min_length(self, chars: usize) -> Self
pub fn min_length(self, chars: usize) -> Self
Refuse a value of fewer than chars characters, and render minlength.
Like every rule here, the browser checks it before it submits, and the server checks it again on the trimmed value once the field’s type parses it. A blank value is the field’s blank answer, which no rule refuses, and a value the record already stores is not checked again. A length counts characters, where a browser counts UTF-16 units.
Sourcepub fn max_length(self, chars: usize) -> Self
pub fn max_length(self, chars: usize) -> Self
Refuse a value of more than chars characters, and render maxlength, which stops the
browser’s input there.
Sourcepub fn min(self, bound: impl Display) -> Self
pub fn min(self, bound: impl Display) -> Self
Refuse a value below bound, and render min.
The bound is a value of the field’s type, which orders: a number, or a jiff date, time,
date and time, or timestamp. .min(0) on an i64 field, .min(date(2024, 1, 1)) on a
jiff::civil::Date one; a bound the type does not parse or order fails the mount. A time’s
control edits it to the minute, so give a time bound in whole minutes.
Sourcepub fn max(self, bound: impl Display) -> Self
pub fn max(self, bound: impl Display) -> Self
Refuse a value above bound, and render max; min says which bounds a
field takes.
Sourcepub fn pattern(self, pattern: impl Into<String>) -> Self
pub fn pattern(self, pattern: impl Into<String>) -> Self
Refuse a value the regular expression pattern does not match whole, and render it as
the pattern attribute.
The server matches it with the regex crate and the browser as a JavaScript expression in
its v mode, both against the whole value, so write it in the syntax they share: classes,
groups, alternation and repetition. Spell digits [0-9], since the server’s \d matches
other scripts’ digits too; escape a - inside a class, which the browser otherwise refuses
along with the whole pattern; and leave out lookaround, backreferences and inline flags.
One the regex crate does not compile fails the mount. A .multiline textarea renders no
pattern, so only the server checks it there.
Field::text(lens!(Product.sku)).pattern("[A-Z]{3}-[0-9]{4}");