Caravela.Live.Form (Caravela v0.5.0)

Copy Markdown View Source

DSL for declaring form-visibility predicates and async-validation rules on top of Caravela.Live.Domain.

A form-domain module compiles into a regular Caravela.Live.Domain (so all state/updater/event sugar is available) plus a small amount of form-specific introspection consumed by the Svelte form generator (Caravela.Gen.SvelteForm) and by the form LiveView at runtime.

defmodule MyApp.BookFormDomain do
  use Caravela.Live.Form,
    entity: MyApp.Library.V1.Book,
    context_fields: [:current_user]

  state do
    field :book, :map, default: nil
    field :attrs, :map, default: %{}
    field :errors, :map, default: %{}
    field :field_visibility, :map, default: %{}
    field :async_errors, :map, default: %{}
    field :saving, :boolean, default: false
    field :flash_message, :string, default: nil
  end

  visible :published_at, fn assigns ->
    Map.get(assigns.attrs, :published) == true
  end

  visible :price, fn assigns ->
    assigns.current_user.role in [:admin, :editor]
  end

  validate_async :isbn, debounce: 500, fn value, _assigns ->
    case MyApp.ISBNService.validate(value) do
      :ok -> :ok
      {:error, reason} -> {:error, reason}
    end
  end
end

After compilation the module exposes:

  • __caravela_form__/0 — form metadata (entity, context fields, visible/async field lists, debounces).
  • __caravela_form_visibility__/1 — compute the field_visibility map from an assigns map by running every visible predicate.
  • __caravela_form_visible__/2 — per-field visibility predicate (fallback returns true for undeclared fields).
  • __caravela_form_validate_async__/3 — dispatches a field's async validator; returns :ok or {:error, reason}.

Summary

Functions

Declare an async validator for a field.

Declare a visibility predicate for a field. The function receives the LiveView assigns and must return a boolean.

Functions

validate_async(field, opts \\ [], fun)

(macro)

Declare an async validator for a field.

validate_async :isbn, debounce: 500, fn value, assigns ->
  MyApp.ISBNService.validate(value)
end

The validator is a function of arity 2 (value, assigns) that returns :ok or {:error, reason}. The optional :debounce option (milliseconds) is exposed as metadata so the generated Svelte form can debounce client-side input before pushing the "validate_async" event back to the LiveView.

visible(field, fun)

(macro)

Declare a visibility predicate for a field. The function receives the LiveView assigns and must return a boolean.

visible :published_at, fn assigns ->
  Map.get(assigns.attrs, :published) == true
end

The predicate is evaluated server-side; the computed truth value is sent to the Svelte component as field_visibility.<name> so that {#if field_visibility.published_at} renders reactively.