Arsenalist

Arsenalist

I want to show input fields based on the value of a the radio button. Here are the two approaches I tried. This is inside a LiveComponent and I’m on LiveView 1.0.2. What is the best way to implement this simple feature (neither of the below work)?

APPROACH 1

When I click on a radio button, it is selected, but none of the following two ifs evaluate to true so the additional fields are never shown.

    <.form for={@form} phx-change="validate" phx-submit="save" phx-target={@myself}>
      <.input
        label="I am an individual"
        type="radio"
        value="INDIVIDUAL"
        field={@form[:entity_type]}
      />
      <.input
        label="I represent a company"
        type="radio"
        value="COMPANY"
        field={@form[:entity_type]}
      />
      <%= if Phoenix.HTML.Form.input_value(@form, :entity_type) == "INDIVIDUAL" do %>
        <.input label="First Name" type="text" field={@form[:first_name]} />
        <.input label="Last Name" type="text" field={@form[:last_name]} />
      <% end %>
      <%= if Phoenix.HTML.Form.input_value(@form, :entity_type) == "COMPANY" do %>
        <.input label="Company Name" type="text" field={@form[:company_name]} />
      <% end %>
    </.form>

Here is the LiveView code:

  def mount(socket) do
    form_attributes = %{
      "first_name" => "",
      "last_name" => "",
      "company_name" => "",
      "entity_type" => ""
    }

    {:ok,
     assign(
      socket,
       :form,
       to_form(form_attributes)
     )
    }
  end

  def handle_event("validate", _params, socket) do
    {:noreply, socket}
  end

APPROACH 2

After not getting this to work I also tried this approach where I set a new variable to track which entity_type is selected. This resulted in the if condition being executed, but the radio button not being selected and I have to click it again for it to be selected. Here’s a video: Area - Dubz

    <.form for={@form} phx-change="validate" phx-submit="save" phx-target={@myself}>
      <.input
        label="I am an individual"
        type="radio"
        value="INDIVIDUAL"
        field={@form[:entity_type]}
        phx-change="entity_type_changed"
        phx-target={@myself}
      />
      <.input
        label="I represent a company"
        type="radio"
        value="COMPANY"
        field={@form[:entity_type]}
        phx-change="entity_type_changed"
        phx-target={@myself}
      />
      <%= if @entity_type_selected == "INDIVIDUAL" do %>
        <.input label="First Name" type="text" field={@form[:first_name]} />
        <.input label="Last Name" type="text" field={@form[:last_name]} />
      <% end %>
      <%= if @entity_type_selected == "COMPANY" do %>
        <.input label="Company Name" type="text" field={@form[:company_name]} />
      <% end %>
    </.form>
  def mount(socket) do
    form_attributes = %{
      "first_name" => "",
      "last_name" => "",
      "company_name" => "",
      "entity_type" => ""
    }

    {:ok,
     assign(
      socket,
       :form,
       to_form(form_attributes)
     )
     |> assign(:entity_type_selected, "")
    }
  end

  def handle_event("entity_type_changed", %{"entity_type" => entity_type} = params, socket) do
    {:noreply, assign(socket, :entity_type_selected, entity_type)}
  end

Showing Posts 1 to 6

garrison

garrison

When your "validate" event is called, the form sends back the params in the params variable (the second argument to handle_event/3). You have to actually assign the new values back to the socket - currently you are just throwing them away.

{:noreply, assign(socket, :form, to_form(params))}

This is why your first approach doesn’t work. It’s also why your second approach doesn’t work - you are updating the variable, but you’re also throwing away the new params, so when the update comes back from the server it clobbers the radio button (since the server state was never changed).

LostKobrakai

LostKobrakai

The form abstraction needs to deal with invalid and partial values and various types of values. Hence it’s not the best place to check if an input is of a certain value. I’d suggest checking Ecto.Changeset.get_field(@form.source, field) instead if the form is based on a changeset.

Arsenalist

Arsenalist OP

Thank you, I tried that and it only partially worked. The if conditions worked fine but the radio button remained unselected in the UI. Here’s a video: ex - Dubz

LiveComponent

  def handle_event("validate", %{"entity_type" => entity_type} = params, socket) do
    {:noreply,
     assign(socket, :form, to_form(params))
     |> assign(:entity_type_selected, entity_type)
     |> IO.inspect()}
  end

  def handle_event("validate", params, socket) do
    {:noreply, assign(socket, :form, to_form(params))}
  end

Template:

      <.input
        label="I am an individual"
        type="radio"
        value="INDIVIDUAL"
        field={@form[:entity_type]}
      />
      <.input
        label="I represent a company"
        type="radio"
        value="COMPANY"
        field={@form[:entity_type]}
      />
      <%= if @entity_type_selected == "INDIVIDUAL" do %>
        <.input label="First Name" type="text" field={@form[:first_name]} />
        <.input label="Last Name" type="text" field={@form[:last_name]} />
      <% end %>
      <%= if @entity_type_selected == "COMPANY" do %>
        <.input label="Company Name" type="text" field={@form[:company_name]} />
      <% end %>

Here’s also the core_component.ex part which renders the radio button:

  def input(%{type: "radio"} = assigns) do
    ~H"""
    <div class="flex flex-col gap-2">
      <div class="flex gap-2 items-center">
        <input
          type={@type}
          name={@name}
          id={@id}
          value={Phoenix.HTML.Form.normalize_value(@type, @value)}
          class={[
            "block rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
            @errors == [] && "border-zinc-300 focus:border-zinc-400",
            @errors != [] && "border-rose-400 focus:border-rose-400"
          ]}
          {@rest}
        />
        <.label for={@id}>{@label}</.label>
      </div>
      <div>
        <.error :for={msg <- @errors}>{msg}</.error>
      </div>
    </div>
    """
  end

The IO.inspect prints this in the console:

#Phoenix.LiveView.Socket<
  id: "phx-GBnFKa97P70hyQAI",
  endpoint: AmplifyWeb.Endpoint,
  view: AmplifyWeb.PaymentDestinations,
  parent_pid: nil,
  root_pid: #PID<0.917.0>,
  router: AmplifyWeb.Router,
  assigns: %{
    id: "cpd",
    open: true,
    form: %Phoenix.HTML.Form{
      source: %{
        "_target" => ["entity_type"],
        "_unused_first_name" => "",
        "_unused_last_name" => "",
        "entity_type" => "COMPANY",
        "first_name" => "",
        "last_name" => ""
      },
      impl: Phoenix.HTML.FormData.Map,
      id: nil,
      name: nil,
      data: %{},
      action: nil,
      hidden: [],
      params: %{
        "_target" => ["entity_type"],
        "_unused_first_name" => "",
        "_unused_last_name" => "",
        "entity_type" => "COMPANY",
        "first_name" => "",
        "last_name" => ""
      },
      errors: [],
      options: [],
      index: nil
    },
    source: "payment_destinations_list",
    __changed__: %{
      form: %Phoenix.HTML.Form{
        source: %{
          "_target" => ["entity_type"],
          "_unused_company_name" => "",
          "company_name" => "",
          "entity_type" => "INDIVIDUAL"
        },
        impl: Phoenix.HTML.FormData.Map,
        id: nil,
        name: nil,
        data: %{},
        action: nil,
        hidden: [],
        params: %{
          "_target" => ["entity_type"],
          "_unused_company_name" => "",
          "company_name" => "",
          "entity_type" => "INDIVIDUAL"
        },
        errors: [],
        options: [],
        index: nil
      },
      entity_type_selected: true
    },
    flash: %{},
    entity_type_selected: "COMPANY",
    account_id: "acct_01HFFEWHEP5HA4F0GQPVYBBX3X",
    myself: %Phoenix.LiveComponent.CID{cid: 1}
  },
  transport_pid: #PID<0.910.0>,
  ...
>
Arsenalist

Arsenalist OP

BTW, I also tried adding this to the radio input but same effect:

      <.input
       id="company_option"
        label="I represent a company"
        type="radio"
        value="COMPANY"
        field={@form[:entity_type]}
        checked={@entity_type_selected == "COMPANY"} # new line added

    />``
garrison

garrison

You need to handle the checked state in your input component, it’s not actually added to the real <input> element. It would probably be better to compare the value there instead of passing in checked anyway.

Also, radio buttons are not supposed to share the same id, only the name.

sreyansjain

sreyansjain

You can try this. I am on mobile so I am a bit limited now.

<.input
  label="I am an individual"
  type="radio"
  value="INDIVIDUAL"
  field={@form[:entity_type]}
  checked={@form[:entity_type].value && @form[:entity_type].value == "INDIVIDUAL"}
/>

For conditional field visibility this would work too

<.input :if={@form[:entity_type].value && @form[:entity_type].value == "INDIVIDUAL"} label="First Name" type="text" field={@form[:first_name]} />

Need to update the form in the validate event

def handle_event("validate", params, socket) do
  {:noreply, assign(socket, :form, to_form(params))}
end
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews