From b73c96de12359b32359190feca52ab4b6939e922 Mon Sep 17 00:00:00 2001 From: Frerich Raabe Date: Fri, 28 Nov 2025 12:25:43 +0100 Subject: [PATCH] Permit holding custom data in options 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""" <:option :let={option}> <.student student={option.student} /> """ 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. --- lib/live_select/component.ex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/live_select/component.ex b/lib/live_select/component.ex index 7eccb3b..e6bff6e 100644 --- a/lib/live_select/component.ex +++ b/lib/live_select/component.ex @@ -534,13 +534,18 @@ defmodule LiveSelect.Component do end defp client_select(socket, extra_params) do + cleansed_selection = + Enum.map(socket.assigns.selection, fn option -> + Map.take(option, [:disabled, :label, :value, :tag_label]) + end) + socket |> push_event( "select", %{ id: socket.assigns.id, mode: socket.assigns.mode, - selection: socket.assigns.selection + selection: cleansed_selection } |> Map.merge(extra_params) )