lessless
Is my understanding of component composition/communication model correct?
Hi,
My background in components composition is mostly with DDAU in Ember.js. So it naturally serves me as a jump pad as I wrap my head around Live View and wonder how close my mental model is to the idiomatic LiveView approach.
Let me illustrate my thinking process with an example of breaking a modal component further down into smaller components.
I have a Dashboard LiveView within which there is a UploadModal that hosts PatientSelector component.
PatientSelector is a typical typeahead: the clinician types patient names and sees a list of patients whose names match his query.
The selected patient becomes a value of that typeahead and must be propagated to the parent UploadModal component.
───────────────────────────────Chronological flow─────────────────────────────────▶
┌───────────────────────────────────────────────────────────────────────────────────┐
│ Upload Modal Live Component │
│ │
└─────────────────────────────────────────────▲────────────────────────────┬────────┘
│ │ │
│ │ │
destination │ │
for`on_selected` event sends `patient_selected` updates `selected_patient`
and `selected_patient` event to `on_selected` │
property target │
│ │ │
│ │ │
┌─────▼──────────────────────────────────────┴────────────────────────────▼────────┐
│ PatientSelector Live Component │
│ │
└──────────────────────────────────────────────────────────────────────────────────┘
▲
│
│
User selects patient
│
│
│
│
┌───────────────────┐
│ User │
└───────────────────┘
The cornerstone of this component is an input which triggers a patient lookup
<input
phx-debounce="100"
phx-focus={show_results()}
phx-blur={hide_results()}
name="search"
type="text"
autocomplete="off"
placeholder="Search by patient name or email"
value={@selected_patient.name}
/>
and then there is an autocompletion list in which items are entry points to patient selection:
<ul id="upload-modal-patient-selector-results" class="rounded">
<%= for patient <- @found_patients do %>
<li
phx-click="patient_selected"
phx-value-selected-patient-id={@patient.id}
phx-target={@myself}
>
As I understand it - I can’t assign a struct to phx-value-*, so instead, I’m setting selected patient id phx-value-selected-patient-id={@patient.id} .
Then, since PatientSelector keeps a list of found_patients in its state, I can pull Patient from that list in the event handler and send it to the parent component
def handle_event("patient_selected", %{"selected-patient-id" => selected_patient_id}, socket) do
selected_patient = Enum.find(socket.assigns.found_patients, &(&1.id == selected_patient_id))
send_update(socket.assigns.on_selected.module,
id: socket.assigns.on_selected.id,
selected_patient: selected_patient,
event: :patient_selected
)
{:noreply, socket}
end
Now, because selected_patient is passed to the PatientSelector, when I update it in the parent component, the child component also gets it.
<!-- somewhere in the parent component template -->
<.live_component module={PatientSelector} id="patient-selector-component" selected_patient={@selected_patient} on_selected={%{module: __MODULE__, id: @id}} current_user={@current_user} />
defmodule UploadModal do
use ObfuscatedWeb, :live_component
alias PatientSelector
def mount(socket) do
{:ok, assign(socket, :selected_patient, %{name: nil})}
end
def update(%{event: :patient_selected, selected_patient: selected_patient}, socket) do
{:ok, assign(socket, :selected_patient, selected_patient)}
end
def update(assigns, socket) do
{:ok, assign(socket, assigns)}
end
end
It all works fine, but I wonder if I’m going against the LV programming model with this or not. The primary motivation behind this wiring is to make the upload modal reusable without exposing its wiring/implementation details to hosting LiveView.
Pinging @chrismccord like he’s not busy enough already ![]()
UPDATE: I’m not sure how it happens but after patient being selected for the first time update in the parent component is not triggered, but I still can see selected patient name in the parent component’s template.
Popular in Discussions
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










