Skip to main content

EmbeddedForm

Derive Macro EmbeddedForm 

Source
#[derive(EmbeddedForm)]
{
    // Attributes available to this derive:
    #[form]
}
Expand description

Derives EmbeddedForm for an embedded struct or enum.

Builds the schema node and converts the value through that node’s keys.

#[derive(Debug, Clone, toasty::Embed, tablo_core::EmbeddedForm)]
pub enum Publication {
    #[column(variant = 1)]
    Scheduled {
        #[shared(timestamp)]
        #[form(label = "Publication timestamp")]
        scheduled_at: String,
        scheduled_for: String,
    },
    #[column(variant = 2)]
    Published {
        #[shared(timestamp)]
        published_at: String,
        canonical_url: String,
    },
}

// form declaration — no field bindings written by hand
Section::new("Publication").schema(Publication::form(Post::fields().publication()));

§How a field is classified

A field marked #[form(embed)] is another embedded value, delegated to its own EmbeddedForm. Every other field is a scalar: one column, read and written through FormScalar (String, a TypedValue type, an Options enum, or an Option of one). A scalar of another type fails to compile at the field, naming the trait. An empty scalar is its blank answer — its declared #[form(blank = ..)], None for an Option, false for a bool, "" for an #[form(optional)] String — and a scalar with none is required: its control renders required and the parse refuses its key.

§Which variant an enum reads

A named discriminant always wins, and an undeclared one is refused; otherwise the first variant, in declaration order, with a payload of its own submitted — a #[shared(..)] column belongs to several variants and never selects one; otherwise the first variant.

A #[shared(..)] column renders once. A variant that does not declare it hides the column: the codec neither reads nor submits it there, so that variant needs no answer for the column, even when the column is required.

An enum renders a choice of variant and one group of fields per variant. The page shows only the chosen variant’s group, and the variant can change on edit. The submitted variant decides which fields are read and validated, so a stale value in a hidden group never blocks a submit; a hidden group’s controls are disabled, so the browser neither validates nor submits them. Without JavaScript only the stored variant’s group shows, so a create page offers no variant’s fields, and the variant choice still decides.

§Not supported

A #[document] field, a relation, an enum nested inside an enum variant, and a tuple struct.

§Per-field attributes

  • #[form(embed)] — a nested EmbeddedForm value.
  • #[form(label = "Canonical URL")] — the control’s label (default: the field name in sentence case, canonical_url → “Canonical url”).
  • #[form(multiline = 3)] — a <textarea> of 3 rows.
  • #[form(blank = ..)] — what an empty submission reads as.
  • #[form(optional)] on a String — an empty submission reads as "".

Anything else in #[form(..)] is a compile error, as are label, multiline, blank and optional on an embedded value, blank or optional on an Option, and optional on a type other than String. Derives EmbeddedForm for an embedded struct or enum; documented on the tablo-core re-export.