hendri-tobing
Populate a Select field based on previous Select field
I have database tables: Companies, Devices, and Signs. The device belongs_to a Company and the Company has_many Signs.
I want to show on the new device form:
- a select box of the existing Companies, and
- a select box of the Signs that is populated based on the company selection.
The select box of the signs is dynamically changed if the selected company changed.
How to achieve this?
So far this is my device_controller.ex
defmodule PortalWeb.DeviceController do
use PortalWeb, :controller
alias Portal.Fleet
alias Portal.Fleet.Device
def create(conn, %{"device" => device_params}) do
with {:ok, %Device{} = device} <- Fleet.create_device_customer(device_params) do
conn
|> put_flash(:info, "The device is created successfuly")
|> redirect(to: Routes.page_path(conn, :index))
end
end
def new(conn, _params) do
changeset = Fleet.change_device(%Device{})
customers = Fleet.list_customers()
|> Enum.map(&{"#{&1.name}", &1.id})
render(conn, "new.html", changeset: changeset, customers: customers)
end
end
Thank you.
Most Liked
sfusato
Basically you would have a phx-change event on the form which will fire on every input change. Then in the handle_event callback you will pattern match on your Company select value and see if it changed from the one you have in your socket assigns. If it did, fetch the new Signs and re-assign. This will re-render your liveview automatically.
While there isn’t an example exactly like your use-case in it, phoenix_live_view_example is a good way to peek at how things work.
Later edit: found this (the “Bike comparison” example)
hendri-tobing
Thank you for the suggestion and example. I managed to populate the select field by using LiveView.
As suggested, I use phx-change that will pattern match the Company select value, then fetch the new Sign based on the value. Also assign the selected value to the Company select field.
This is part of my LiveView file.
def render(assigns), do: LiveDeviceView.render("form.html", assigns)
def mount(session, socket) do
companies = Portal.Fleet.list_companies()
selected_company = nil
{:ok,
assign(socket,
changeset: Fleet.change_device(%Device{}),
companies: companies,
selected_company: selected_company,
signs: [],
)}
end
def handle_event("populate_sign", %{"device" => params}, socket) do
signs = Fleet.get_company(String.to_integer(params["company_id"]))
companies = Portal.Fleet.list_companies()
changeset = Fleet.change_device(%Device{})
selected_company = String.to_integer(params["company_id"])
{:noreply, assign(socket, signs: signs, companies: companies, selected_company: selected_company, changeset: changeset)}
end
form.html.leex
<%= f = form_for @changeset, "#", [phx_change: :populate_sign, phx_submit: :save] %>
<%= label f, :company_id %>
<%= select f, :company_id, Enum.map(@companies, &{&1.name, &1.id}), prompt: "Select a company", selected: @selected_company %>
<%= error_tag f, :companies %>
<%= if @signs == [] do %>
<%= if @selected_company != nil do %>
<p>This company has no Sign</p>
<%= link "Add a new sign for this company", to: Routes.company_path(@socket, :new) %>
<% end %>
<% else %>
<%= label f, :sign_id %>
<%= select f, :sign_id, Enum.map(@signs, &{&1.name, &1.id}), prompt: "Select a sign" %>
<%= error_tag f, :signs %>
<% end %>
<%= submit "Save", phx_disable_with: "Saving..." %>
</div>
</form>
Thank you again for all responses.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








