miguelcoba

miguelcoba

Does anyone have a working example of polymorphic_embed working with LiveView 1.1? Specifically the live view part (the backend part seems to work just fine).

I have followed the documentation but I see nothing on the browser. Nothing is emitted on the html if I inspect it.

Looking at the github issues/pull requests, it seems like it is kinda abandoned for the last year.

Any pointers to a working example or a fork that works for current (1.1) live view?

Thanks!

Showing Posts 1 to 4

brownerd

brownerd

I’ve been using it, but in a project that’s still in development. Its working great for me. Do you have any code to post, like the Schema and LiveView that use polymorphic_embed?

I do remember being confused about the usage, but it working.

miguelcoba

miguelcoba OP

it’s very simple a client has polymorphic name depending on its type (individual or legal entity):

 defmodule MyApp.Client do

  schema "clients" do
    field :client_type, Ecto.Enum, values: [:legal_entity, :individual]

    polymorphic_embeds_one(:client_name,
      types: [
        legal_entity: LegalEntityName,
        individual: IndividualName
      ],
      on_replace: :update
    )
  end
end

defmodule MyApp.LegalEntityName do
  embedded_schema do
    field :corporate_name, :string
    field :trade_name, :string
  end
end

defmodule MyApp.IndividualName do

  embedded_schema do
    field :name, :string
    field :first_surname, :string
    field :second_surname, :string
  end
end

defmodule MyAppWeb.ClientLive.Form do
  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope}>
      <.form for={@form} id="client-form" phx-change="validate" phx-submit="save">
        <.input
          field={@form[:client_type]}
          type="select"
          label={gettext("Client type")}
          prompt={gettext("Choose a value")}
          options={ClientType.options()}
        />
        <.polymorphic_embed_inputs_for :let={name} field={@form[:client_name]}>
          <.input field={name[:corporate_name]} type="text" label={gettext("Corporate name")} />
          <%= case source_module(name) do %>
            <% LegalEntityName -> %>
              <.input field={name[:trade_name]} type="text" label={gettext("Trade name")} />
            <% IndividualName -> %>
              <.input field={name[:name]} type="text" label={gettext("Name")} />
              <.input field={name[:first_surname]} type="text" label={gettext("First surname")} />
          <% end %>
        </.polymorphic_embed_inputs_for>
      </.form>
    </Layouts.app>
    """
  end

  defp apply_action(socket, :new, _params) do
    client = %Client{user_id: socket.assigns.current_scope.user.id}

    socket
    |> assign(:client, client)
    |> assign(:form, to_form(Clients.change_client(socket.assigns.current_scope, client)))
  end
end

When the page is rendered, the `client_type` dropdown and the form renders just fine, but the polymorphic_embed does not. The html doesn’t even contain anything other than the heex debug comments, but nothing in between.

<!-- @caller lib/myapp_web/live/client_live/form.ex:36  -->
<!-- @caller lib/myapp_web/live/client_live/form.ex:46  -->

I have tried a lot of variations:

  • setting `type_field_name`
  • using `use_parent_field_for_type` to point to the `client_type` dropdown
  • setting ` %Client{user_id: socket.assigns.current_scope.user.id, client_type: :individual}` on the `apply_action`.

In summary, I don’t know if I’m using this library the way it is supposed to be used. What I want is:

  • on new form, show empty fields for the type selected in the `client_type` dropdown (or a default generated when creating the struct passed to `to_form`
  • on edit, render the fields with the data fetched from the Repo and loaded into the struct.
  • dinamically change the fields shown depending on the client_type.

Nothing too complicated in my opinion.

Am I using this library correctly?

Thanks

miguelcoba

miguelcoba OP

Ok, I think I got it to work:

I added a default to the client_type:

    field :client_type, Ecto.Enum, values: [:legal_entity, :individual], default: :legal_entity

Then the new puts the correct embedded struct, depending on the `client_type`:



  defp apply_action(socket, :new, _params) do
    client = %Client{user_id: socket.assigns.current_scope.user.id}

    client =
      case client.client_type do
        :legal_entity ->
          %Client{client | client_name: %LegalEntityName{}}

        :individual ->
          %Client{client | client_name: %IndividualName{}}
      end

    socket
    |> assign(:page_title, gettext("New client"))
    |> assign(:client, client)
    |> assign(:form, to_form(Clients.change_client(socket.assigns.current_scope, client)))
  end



And when validating, if the `client_type` changed, I change the polymorphic_embed struct too:


  @impl true
  def handle_event("validate", %{"client" => client_params}, socket) do
    changeset =
      Clients.change_client(socket.assigns.current_scope, socket.assigns.client, client_params)

    changeset =
      case Ecto.Changeset.get_change(changeset, :client_type) do
        nil -> changeset
        :legal_entity -> Ecto.Changeset.put_change(changeset, :client_name, %LegalEntityName{})
        :individual -> Ecto.Changeset.put_change(changeset, :client_name, %IndividualName{})
      end

    {:noreply, assign(socket, form: to_form(changeset, action: :validate))}
  end

The problem with replacing the client_name on the changeset when `client_type` changes is that the previous values are lost, but is something I can live with.

Thanks!

brownerd

brownerd

Cool! Sorry for the late response, but I’m glad you figure it out. Like I said, I also remember running into some walls getting it to work the way I though it was supposed to. Like you, I eventually got it working and it has been great for me ever since. Best regards!

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
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
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
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
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
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
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews