MishkaGervaz.Form.Web.DataLoader.RelationLoader (MishkaGervaz v0.0.2)

Copy Markdown View Source

Loads options for relation/select fields in forms.

Follows the same pattern as MishkaGervaz.Table.Web.DataLoader.RelationLoader.

Modes

  • :static - Load all options at once (page: false)
  • :load_more - Paginated with load more button
  • :search - Search with pagination (single select)
  • :search_multi - Search with pagination (multi select)

Action Resolution

For master users, tries :master_read → :read_any → :read. For tenant users, uses :read with the user's site_id as tenant.

User Override

defmodule MyApp.Form.RelationLoader do
  use MishkaGervaz.Form.Web.DataLoader.RelationLoader

  def load_options(field, state, opts) do
    super(field, state, opts)
  end
end

Top-level helpers (load_all_options/4, load_paginated_options/6, build_options/4, prepend_nil_option/2, resolve_display_field/2, resolve_load_action/3, get_tenant/1, maybe_apply_search/2, maybe_apply_custom_load/3, resolve_selected_fallback/7) are public so user overrides can reuse them — they live outside the __using__ macro to avoid per-consumer compile cost.

See MishkaGervaz.Form.Web.DataLoader, MishkaGervaz.Form.Web.DataLoader.Helpers, MishkaGervaz.Form.Web.State, and the sibling sub-builders RecordLoader, TenantResolver, HookRunner. The table-side counterpart is MishkaGervaz.Table.Web.DataLoader.RelationLoader.

Summary

Functions

A resource-less field's own options: its list, its zero-arity function's list, or — for fn state -> options end — what the form state makes of them now.

The options flattened, a grouped one labelled "Group · Label" as it reads once picked.

A record's option label, by its display_field as MishkaGervaz.Helpers.resolve_label/3 reads it: an attribute, fn record -> label end, or fn record, state -> label end given the form state. An attribute the record leaves nil reads as the record's id.

The options whose label holds search_term. A group {group_label, [options]} is kept whole when its own label holds it, else with the options that do, and left out when none does.

Functions

field_options(arg1, state)

@spec field_options(map(), map()) :: list()

A resource-less field's own options: its list, its zero-arity function's list, or — for fn state -> options end — what the form state makes of them now.

flat_options(options)

@spec flat_options(list()) :: [{String.t(), any()}]

The options flattened, a grouped one labelled "Group · Label" as it reads once picked.

get_display_value(record, display_field, state \\ nil)

@spec get_display_value(map(), atom() | function(), map() | nil) :: String.t()

A record's option label, by its display_field as MishkaGervaz.Helpers.resolve_label/3 reads it: an attribute, fn record -> label end, or fn record, state -> label end given the form state. An attribute the record leaves nil reads as the record's id.

iex> MishkaGervaz.Form.Web.DataLoader.RelationLoader.get_display_value(
...>   %{id: "v-1", version_name: nil},
...>   :version_name
...> )
"v-1"

matching_options(options, search_term)

@spec matching_options(list(), String.t()) :: list()

The options whose label holds search_term. A group {group_label, [options]} is kept whole when its own label holds it, else with the options that do, and left out when none does.