Configuration struct that defines the complete form structure using SurveyJS-compatible format.
An Instance represents a complete form definition with all its elements (questions and panels), and validators.
SurveyJS Compatibility
This library uses SurveyJS-compatible JSON format for form definitions. See: https://surveyjs.io/form-library/documentation
Example
iex> instance = %DynamicForm.Instance{
...> id: "contact-form",
...> title: "Contact Form",
...> description: "Get in touch with us",
...> elements: [
...> %DynamicForm.Instance.Element{
...> name: "intro",
...> type: "html",
...> html: "<h2>Contact Information</h2>"
...> },
...> %DynamicForm.Instance.Question{
...> name: "email",
...> type: "text",
...> inputType: "email",
...> title: "Email Address",
...> isRequired: true
...> }
...> ]
...> }JSON Encoding/Decoding
Instances can be encoded to JSON and parsed back:
# Encode to JSON
json = Jason.encode!(instance)
# Parse from a JSON string or map
instance = DynamicForm.Parser.FromData.parse!(json)
instance = DynamicForm.Parser.FromData.parse!(map)Slot-Defined Instances
Instances can also be built from <:field> slot entries via DynamicForm.form/1
(see DynamicForm.Parser.FromComponent). Questions and elements defined with a
slot body carry the raw slot entry in their :slot field so the renderer can
call Phoenix.Component.render_slot/2 on it. The :slot field holds a
closure, so it is never JSON-encoded; use strip_slots/1 to compare two
instances by definition alone.
Summary
Functions
Whether a definition's display text is blank: nil, false, or "".
The text labelling a question, or nil when the definition asks for none.
The mark shown beside a required question's label, or nil for none.
Returns a copy of the instance with all :slot fields removed.
Types
@type t() :: %DynamicForm.Instance{ description: String.t() | nil, elements: [Question.t() | Element.t()], id: String.t(), inserted_at: DateTime.t() | nil, metadata: map(), title: String.t() | nil, updated_at: DateTime.t() | nil }
Functions
Whether a definition's display text is blank: nil, false, or "".
Titles, labels, and headings accept all three to mean "render nothing", so a template can compute one without special-casing the absent case:
<:group name="totals" title={@compact && gettext("Totals")} />
The text labelling a question, or nil when the definition asks for none.
A question with no title at all falls back to its capitalized name, so
<:field type="text" name="email" /> still labels itself "Email". A title
the definition sets blank (nil, false, or "") means "no label", and
returns nil — callers render no label element, and no required marker,
since there would be nothing for the marker to sit beside.
The mark shown beside a required question's label, or nil for none.
A question that sets no requiredLabel uses "*". One that sets it blank
(nil, false, or "") suppresses the mark while staying required, and any
other value replaces it — "(required)", say.
Returns a copy of the instance with all :slot fields removed.
Slot-defined elements (see DynamicForm.Parser.FromComponent) carry their raw
slot entry — including its inner_block closure — in the :slot field.
Closures capture template assigns, so two otherwise-identical instances can
compare unequal whenever those assigns change. Stripping the slots yields the
form definition alone, which compares reliably with ==.