Skip to content

Conversation

@frerich
Copy link

@frerich frerich commented Nov 28, 2025

When using the <:option> slot, it is convenient to be able to store other data in the options solely for customising the rendering of an option. E.g.:

  def handle_event("live_select_change", %{"id" => select_id, "text" => text}, socket) do
    students = fetch_student_suggestions(text)

    options = Enum.map(suggestions, &%{label: &1.full_name, value: &1.id, student: &1})
    # ...
  end

  def render(assigns) do
    ~H"""
      <LiveSelect.live_select field={f[:student_id]} >
        <:option :let={option}>
          <.student student={option.student} />
        </:option>
      </LiveSelect.live_select>
    """
  end

However, all fields in an option currently need to support encoding to JSON since the list of selected options is sent to the client. Thus, only custom data fields which support encoding to JSON can be included in the options.

This commit changes that by cleansing the set of selected options before sending them to the client: any fields other than

  • :label
  • :value
  • :disabled
  • :tag_label

are omitted, the first three seem to be the 'canonical set' which the normalize_option/1 function returns, :tag_label is a supported optional field.

That way, whatever custom data is stored on options for customising the rendering is not sent to the client - and does not require defining a protocol implementation for e.g. Jason.Encoder either.

When using the <:option> slot, it is convenient to be able to
store other data in the options solely for customising the rendering of
an option. E.g.:

```elixir
  def handle_event("live_select_change", %{"id" => select_id, "text" => text}, socket) do
    students = fetch_student_suggestions(text)

    options = Enum.map(suggestions, &%{label: &1.full_name, value: &1.id, student: &1})
    # ...
  end

  def render(assigns) do
    ~H"""
      <LiveSelect.live_select field={f[:student_id]} >
        <:option :let={option}>
          <.student student={option.student} />
        </:option>
      </LiveSelect.live_select>
    """
  end
```

However, all fields in an option currently need to support encoding to
JSON since the list of selected options is sent to the client. Thus,
only custom data fields which support encoding to JSON can be included
in the options.

This commit changes that by cleansing the set of selected options before
sending them to the client: any fields other than

* `:label`
* `:value`
* `:disabled`
* `:tag_label`

are omitted, these first three seem to be the 'canonical set' which the
`normalize_option/1` function returns, `:tag_label` is a supported
optional field.

That way, whatever custom data is stored on options for customising the
rendering is not sent to the client - and does not require defining a
protocol implementation for e.g. Jason.Encoder either.
@frerich frerich force-pushed the custom-data-in-options branch from 2829b80 to b73c96d Compare November 28, 2025 11:47
@frerich
Copy link
Author

frerich commented Nov 28, 2025

An alternative approach which is maybe easier to maintain would be to add recognition of a new dedicated field for options, like render_data or such. That way, only that specific value would need to be omitted from the event to the client, i.e. the code can use an exclusion list rather than an inclusion list which might be more open to future extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant