defmodule LivebookWeb.Output.ControlFormComponent do use LivebookWeb, :live_component @impl true def mount(socket) do {:ok, assign(socket, data: %{})} end @impl true def update(assigns, socket) do prev_data = socket.assigns.data socket = assign(socket, assigns) data = Map.new(assigns.attrs.fields, fn {field, input_attrs} -> {field, assigns.input_values[input_attrs.id]} end) if data != prev_data do change_data = for {field, value} <- data, assigns.attrs.report_changes[field], into: %{}, do: {field, value} if change_data != %{} do report_event(socket, %{type: :change, data: change_data}) end end {:ok, assign(socket, data: data)} end @impl true def render(%{attrs: %{type: :form}} = assigns) do ~H"""
<%= for {_field, input_attrs} <- @attrs.fields do %> <.live_component module={LivebookWeb.Output.InputComponent} id={"#{@id}-#{input_attrs.id}"} attrs={input_attrs} input_values={@input_values} local={true} /> <% end %> <%= if @attrs.submit do %>
<% end %>
""" end @impl true def handle_event("submit", %{}, socket) do report_event(socket, %{type: :submit, data: socket.assigns.data}) if socket.assigns.attrs.reset_on_submit do reset_inputs(socket) end {:noreply, socket} end defp report_event(socket, attrs) do topic = socket.assigns.attrs.ref event = Map.merge(%{origin: self()}, attrs) send(socket.assigns.attrs.destination, {:event, topic, event}) end defp reset_inputs(socket) do values = for {field, input_attrs} <- socket.assigns.attrs.fields, field in socket.assigns.attrs.reset_on_submit, do: {input_attrs.id, input_attrs.default} send(self(), {:set_input_values, values, true}) end end