I have a LiveView where I want to render two different live components that each have their own representation of the same module. Think something like Elixir forum’s editor window: a panel with controls on the left, and the formatted output on the right. Both operate on the same content, but each render differently.
I thought about using protocols, something like
# Dashboard.ex
defmodule Dashboard do
defprotocol Editor do
def render(struct)
end
defimpl Editor, for: Avatar do
use Phoenix.LiveComponent
def render(struct) do
~H"""
<div phx-target={@myself}>...</div>
"""
end
def handle_event("event", _, socket) do
{:noreply, socket}
end
end
defprotocol Preview do
def render(struct)
end
defimpl Preview, for: Avatar do
use Phoenix.LiveComponent
def render(struct) do
~H"""
<div phx-target={@myself}>...</div>
"""
end
def handle_event("event", _, socket) do
{:noreply, socket}
end
end
end
Because live_component passes assigns as an enumerable, I’m not sure I can get the behaviour I want here. Does anyone have any suggestions? Should I just stick with pattern matching?
No requirement on Protocol—it looked like a suitable solution at first glance. But yeah, I have a number of structs (and growing) that need to be rendered in 2 or 3 different ways.
I avoided over-engineering by hardcoding at the start, but as the number of structs grew it got tiresome to write all the boilerplate. This is my half-way approach that kinda works, but using the defimpl to call out to another component is a level of indirection I’d rather not have to deal with.
defmodule Dashboard
defprotocol Editor do
def view(component)
end
defmodule Avatar do
use Ecto.Schema
embedded_schema do
field(:url, :string)
end
defimpl Dashboard.Editor do
def view(component)
live_component(Dashboard.Components.Editor.Avatar, [module: component, id: "example"])
end
end
end
defmodule Components do
defmodule Editor do
defmodule Avatar do
use Phoenix.LiveComponent
def render(assigns) do
~H"""
<div>...</div>
"""
end
def handle_event("event", _, socket) do
{:noreply, socket}
end
end
end
defmodule Preview do
defmodule Avatar do
...
end
end
end
end