LiveSelect - Dynamic selection input component for LiveView

Hi all.

I am new to LiveSelect.
I am building an Admin App for Music.
It has Artists and Albums.
Every Album has an Artist.

The Album-Form is a LiveComponent.

I have zwo cases:

  1. I create an Album → I don´t have an Artist
  2. I edit an Album → I have an Artist
@impl true
  def update(assigns, socket) do
    {:ok,
     socket
     |> assign(assigns)
     |> assign_form()}
  end

defp assign_form(%{assigns: %{album: album}} = socket) do
    if album do
      # case 2
      artist = Tuneshg.Music.get_artist_by_id!(album.artist_id)
      form = Tuneshg.Music.form_to_update_album(album)
      # populate the LiveSelect with the name of the Artist
      send_update(LiveSelect.Component, id: "live_select_id", value: {artist.name, artist.id}) 
      socket
      |> assign(artist: artist)
      |> assign(form: to_form(form))
    else
      # case 1
      form = Tuneshg.Music.form_to_create_album()
      assign(socket, form: to_form(form))
    end
  end

Here the Form:

@impl true
  def render(assigns) do
    ~H"""
    <div>
      <.header>
        {@title}
        <:subtitle>Use this form to manage album records in your database.</:subtitle>
      </.header>

      <.simple_form
        for={@form}
        id="album-form"
        phx-target={@myself}
        phx-change="validate"
        phx-submit="save"
      >
        <%= if @form.source.type == :create do %>
          <.input field={@form[:name]} type="text" label="Name" />
          <.input field={@form[:year_released]} type="number" label="Year released" />
          <.input field={@form[:cover_image_url]} type="text" label="Cover image url" />
          <.form :let={f} for={@form} phx-change="change">
            <.live_select
              field={f[:artist_id]}
              id="live_select_id"
              phx-target={@myself}
              label="Artist"
            />
          </.form>
        <% end %>
        <%= if @form.source.type == :update do %>
          <.input field={@form[:name]} type="text" label="Name" />
          <.input field={@form[:year_released]} type="number" label="Year released" />
          <.input field={@form[:cover_image_url]} type="text" label="Cover image url" />
          <.form :let={f} for={@form} phx-change="change">
            <.live_select
              field={f[:artist_id]}
              id="live_select_id"
              phx-target={@myself}
              label="Artist"
            />
          </.form>
        <% end %>

        <:actions>
          <.button phx-disable-with="Saving...">Save Album</.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end

When the user types into the Artist-field the is handle_event(“live_select_change” called

@impl true
  def handle_event("live_select_change", %{"text" => text, "id" => live_select_id}, socket) do
    artists =
      Tuneshg.Music.search_artists!(text)
      |> Enum.map(fn artist -> {artist.name, artist.id} end)

    send_update(LiveSelect.Component, id: live_select_id, options: artists)

    {:noreply, socket}
  end

When the submit botton is clicked, handle_event(“save” is called

def handle_event("save", %{"form" => form_data}, socket) do
    IO.inspect(form_data, label: "form_data")
    IO.inspect(socket.assigns.form, label: "form")

    case AshPhoenix.Form.submit(socket.assigns.form, params: form_data) do
      {:ok, album} ->
        notify_parent({:saved, album})

        socket =
          socket
          |> put_flash(:info, "Album #{socket.assigns.form.source.type} saved successfully")
          |> push_patch(to: socket.assigns.patch)

        {:noreply, socket}

      {:error, form} ->
        {:noreply, assign(socket, form: form)}
    end
  end

That works well for case 1 (Create an Album), although the Artist-Field flashes shortly, when the Artist name is inserted.
Is there a better way to do the insert?

My real problem is the case 2 (edit an exiting Album which already has an Artist.
I changed the Artist name from Heiko to “Zombie Kittens!!”

When I change the Artist and submit, the Artist is NOT changed!

I did an IO.inspect on the form_data and socket.assigns.form.
The form_data is correct:

form_data: %{
  "artist_id" => "f1cec0aa-50bd-4913-aad7-33b56df8b8eb",
  "artist_id_text_input" => "Zombie Kittens!!",
  "cover_image_url" => "",
  "name" => "Heikos Album",
  "year_released" => "2025"
}

The form looks this way:

form: %Phoenix.HTML.Form{
  source: #AshPhoenix.Form<
    resource: Tuneshg.Music.Album,
    action: :update,
    type: :update,
    params: %{
      "_unused_cover_image_url" => "",
      "_unused_name" => "",
      "_unused_year_released" => "",
      "artist_id" => "f1cec0aa-50bd-4913-aad7-33b56df8b8eb",
      "artist_id_text_input" => "Zombie Kittens!!",
      "cover_image_url" => "",
      "name" => "Heikos Album",
      "year_released" => "2025"
    },
    source: #Ash.Changeset<
      domain: Tuneshg.Music,
      action_type: :update,
      action: :update,
      attributes: %{},
      relationships: %{},
      errors: [],
      data: #Tuneshg.Music.Album<
        artist: #Ash.NotLoaded<:relationship, field: :artist>,
        __meta__: #Ecto.Schema.Metadata<:loaded, "albums">,
        id: "321b9718-79c0-404b-b5ed-0c43f2845aa2",
        name: "Heikos Album",
        year_released: 2025,
        cover_image_url: nil,
        inserted_at: ~U[2025-02-28 05:25:17.727489Z],
        updated_at: ~U[2025-03-01 09:27:11.285160Z],
        artist_id: "e71d98b5-2eee-478c-ad2d-cfcbd4d02f1f",
        aggregates: %{},
        calculations: %{},
        ...
      >,
      valid?: true
    >,
    name: "form",
    data: #Tuneshg.Music.Album<
      artist: #Ash.NotLoaded<:relationship, field: :artist>,
      __meta__: #Ecto.Schema.Metadata<:loaded, "albums">,
      id: "321b9718-79c0-404b-b5ed-0c43f2845aa2",
      name: "Heikos Album",
      year_released: 2025,
      cover_image_url: nil,
      inserted_at: ~U[2025-02-28 05:25:17.727489Z],
      updated_at: ~U[2025-03-01 09:27:11.285160Z],
      artist_id: "e71d98b5-2eee-478c-ad2d-cfcbd4d02f1f",
      aggregates: %{},
      calculations: %{},
      ...
    >,
    form_keys: [],
    forms: %{},
    domain: Tuneshg.Music,
    method: "put",
    submit_errors: nil,
    id: "form",
    transform_errors: nil,
    original_data: #Tuneshg.Music.Album<
      artist: #Ash.NotLoaded<:relationship, field: :artist>,
      __meta__: #Ecto.Schema.Metadata<:loaded, "albums">,
      id: "321b9718-79c0-404b-b5ed-0c43f2845aa2",
      name: "Heikos Album",
      year_released: 2025,
      cover_image_url: nil,
      inserted_at: ~U[2025-02-28 05:25:17.727489Z],
      updated_at: ~U[2025-03-01 09:27:11.285160Z],
      artist_id: "e71d98b5-2eee-478c-ad2d-cfcbd4d02f1f",
      aggregates: %{},
      calculations: %{},
      ...
    >,
    transform_params: nil,
    prepare_params: nil,
    prepare_source: nil,
    raw_params: %{
      "_unused_cover_image_url" => "",
      "_unused_name" => "",
      "_unused_year_released" => "",
      "artist_id" => "f1cec0aa-50bd-4913-aad7-33b56df8b8eb",
      "artist_id_text_input" => "Zombie Kittens!!",
      "cover_image_url" => "",
      "name" => "Heikos Album",
      "year_released" => "2025"
    },
    warn_on_unhandled_errors?: true,
    any_removed?: false,
    added?: false,
    changed?: false,
    touched_forms: MapSet.new(["_unused_artist_id_text_input",
     "_unused_cover_image_url", "_unused_name", "_unused_year_released",
     "artist_id", "artist_id_text_input", "cover_image_url", "name",
     "year_released"]),
    valid?: true,
    errors: true,
    submitted_once?: false,
    just_submitted?: false,
    ...
  >,
  impl: Phoenix.HTML.FormData.AshPhoenix.Form,
  id: "form",
  name: "form",
  data: #Tuneshg.Music.Album<
    artist: #Ash.NotLoaded<:relationship, field: :artist>,
    __meta__: #Ecto.Schema.Metadata<:loaded, "albums">,
    id: "321b9718-79c0-404b-b5ed-0c43f2845aa2",
    name: "Heikos Album",
    year_released: 2025,
    cover_image_url: nil,
    inserted_at: ~U[2025-02-28 05:25:17.727489Z],
    updated_at: ~U[2025-03-01 09:27:11.285160Z],
    artist_id: "e71d98b5-2eee-478c-ad2d-cfcbd4d02f1f",
    aggregates: %{},
    calculations: %{},
    ...
  >,
  action: nil,
  hidden: [
    _touched: "_unused_artist_id_text_input,_unused_cover_image_url,_unused_name,_unused_year_released,artist_id,artist_id_text_input,cover_image_url,name,year_released",
    _form_type: "update",
    id: "321b9718-79c0-404b-b5ed-0c43f2845aa2"
  ],
  params: %{
    "_unused_cover_image_url" => "",
    "_unused_name" => "",
    "_unused_year_released" => "",
    "artist_id" => "f1cec0aa-50bd-4913-aad7-33b56df8b8eb",
    "artist_id_text_input" => "Zombie Kittens!!",
    "cover_image_url" => "",
    "name" => "Heikos Album",
    "year_released" => "2025"
  },
  errors: [],
  options: [method: "put"],
  index: nil
}

Can anybody tell me please, what I am doing wrong and to fix my problem
or
Is there an easier way accomplishing the edit?
If yes, what do I have to do?

Thank you for your reply, Heiko