Aurora. Uix. Templates. Basic. Renderers. ManyToMany
(Aurora UIX v0.1.5)
Copy Markdown
Renders many-to-many association fields as a list of checkboxes over the related records.
Membership is a set of existing records, not a child the parent owns, so neither of the other
association renderers fits: there is no local foreign key for ManyToOne's single select to bind
to, and OneToMany's "create a new child" flow is the wrong verb — the user picks from records
that already exist. A checkbox list expresses exactly the available operations: the checked set
is the membership, so adding and removing are the same gesture.
Checkboxes rather than a <select multiple>: multi-select needs a modifier-key gesture that is
undiscoverable and unusable on touch, conveys state only through a background colour, and has
nowhere to host bulk controls. The wire format is identical — every box shares the
parent[field][] name, so only checked values are submitted, exactly as only selected options
are — which is why the sentinel below and the host's persistence contract are unchanged.
Reads come from the preloaded association (filter_preloads/1 puts the field in
parsed_opts.preload), and the candidate list comes from the related resource's own
list_function. No join-aware query is involved: both backends resolve the join table during
preload.
Key Features
:formrenders one checkbox per candidate record; the checked boxes are the current membership.- Submits in the same POST as the parent, under
parent[field][]. - Emits a hidden empty-value sentinel so that de-selecting everything still submits the key, which is what makes clearing the last membership possible at all.
- Ships
:default_toggle_all, a tri-state checkbox beside the label: checked when every candidate is a member, unchecked when none is, and a dash when only some are. Clicking a checked toggle clears the membership; clicking it in either other state selects everything. - Registers three action groups through
Aurora.Uix.Action—label(holding the toggle),headerandfooter, the latter two empty — so a host adds, replaces or removes controls in any of the three strips from the layout DSL field options. - Honours the
option_label:field option through the sharedAurora.Uix.Templates.Basic.Helpers.get_select_options/1; when the host declares none, the label falls back to a conventional display column (:name,:title, …) of the related resource's:indexlayout, instead of the record's raw primary key. :showrenders only the current membership as a plain, read-only list — no checkboxes, no candidates that aren't members — with the samedt("No items to show")empty-state messageone_to_manyuses for its own read-only list.- Renders nothing when the related schema is not a registered Aurora UIX resource.
Key Constraints
- The library is transport-only for writes: it renders the input name and forwards the
submitted list of primary keys untouched, and never builds a changeset. Persisting membership is
the host's responsibility —
put_assoc/4in an Ecto changeset, orargument+change manage_relationship(..., type: :append_and_remove)in an Ash action. - Because of the sentinel, the submitted list always carries one blank entry. The host must
reject it. On Ash the argument also needs
constraints: [nil_items?: true], since Ash casts a blank toniland otherwise rejects the list with "no nil values" before anychangeruns. - An Ecto host must declare
on_replace: :deleteon the association, orput_assoc/4raises. That option is also what deletes the join rows — removing a member must never delete the related record itself. html_typestays:select: the field is a set of options, only the widget changed, andget_select_options/1dispatches on it.- The toggle rides the parent form's
phx-change="validate", identified by_target, and costs one extralist_functioncall per click. It must not usephx-click: a click on a checkbox firesclickand thenchange, and the trailing change would re-validate with the pre-click membership and undo the toggle. Nor can it be resolved client-side — the result has to reachauix.form.paramsor the nextphx-changewould discard it. - Requires the related resource to be registered, and the parent to be preloaded for
:showand for editing a persisted record.
Summary
Functions
Renders a many-to-many association field.
Functions
@spec render(map()) :: Phoenix.LiveView.Rendered.t()
Renders a many-to-many association field.
Parameters
assigns(map()) - LiveView assigns containing::field(map()) - Field definition with association details in:data.:auix(map()) - Aurora UIX context with form, entity and layout configuration.
Returns
Phoenix.LiveView.Rendered.t() - Rendered many-to-many association component.