zoedsoupe

zoedsoupe

While searching and studying about live view I found this page of LiveComponent documentation, and reading more carefully about the “cost of a live component”, here: Phoenix.LiveComponent — Phoenix LiveView v1.2.5

Then it gives a not to do example, using a LiveComponent to wrap DOM events, like:

defmodule MyButton do
  use Phoenix.LiveComponent

  def render(assigns) do
    ~H"""
    <button class="css-framework-class" phx-click="click">
      <%= @text %>
    </button>
    """
  end

  def handle_event("click", _, socket) do
    _ = socket.assigns.on_click.()
    {:noreply, socket}
  end
end

So it preferable to use a functional component! Then, it was I did! I have this function component to wrap and style the native DOM button tag:

  attr :style, :string, values: ~w(primary secondary), required: true
  attr :submit, :boolean, default: false
  attr :icon, :atom, required: false, default: nil
  attr :class, :string, default: ""
  attr :rest, :global, doc: ~s(used for phoenix events like "phx-click" and "phx-target")

  slot :inner_block

  def button(assigns) do
    ~H"""
    <button
      type={if @submit, do: "submit", else: "button"}
      class={["btn", "btn-#{@style}", @class]}
      {@rest}
    >
      <.icon :if={@icon} name={@icon} />

      <.text :if={@style == "primary"} size="base" color="text-white-100">
        <%= render_slot(@inner_block) %>
      </.text>

      <.text :if={@style != "primary"} size="base" color="text-blue-80">
        <%= render_slot(@inner_block) %>
      </.text>
    </button>
    """
  end

To be reusable in any phoenix template with a predefined style. My question is, how this function component can handle events, in this case, phx-click?

I used the button like this: https://github.com/peapescarte/pescarte-plataforma/blob/main/lib/pescarte_web/templates/landing_html/show.html.heex#L56-L58

However no event is trigged as can be seen in this little video:

Showing Posts 1 to 10

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

In short, it can’t. In order for a component to receive events it needs to be a stateful component that does use Phoenix.LiveComponent in its own module.

You generally also need to phx-target={@myself} to ensure that the events go to your component.

cmo

cmo

Function components do not handle events. Handle them in the parent liveview or livecomponent.

On a side note, this could be shorter:

<.text :if={@style == "primary"} size="base" color="text-white-100">
   <%= render_slot(@inner_block) %>
</.text>

<.text :if={@style != "primary"} size="base" color="text-blue-80">
  <%= render_slot(@inner_block) %>
</.text>

Could be:

<.text size="base" color={if @style == "primary", do: "text-white-100", else: "text-blue-80">
   <%= render_slot(@inner_block) %>
</.text>
zoedsoupe

zoedsoupe OP

so the template needs to be a live view and not a raw html template, right? Ok, this explain a lot! I’ll try to do this!

Oh, thanks for this little tip, I implement so fast I didn’t noticed haha. Actually I really would like to se a :else and :if-else directive like vue in the future, although it’s not mandatory

zoedsoupe

zoedsoupe OP

HEEx templates can be both live view or not, depending the usage of the screen! Ok, I need to practice more this concept

zoedsoupe

zoedsoupe OP

but phx-target only works inside a live view template, right? then for a button component phx-target to @myself doesn’t make much sense as it need to handle dozens of different events in different screens, not related.

I now see the problem is I’m trying to handle an event on a “raw” html (heex) template and not a live view

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

I don’t really understand what this means. A functional component used by a root live view is still “in live view”. If you have a phx-click on a functional component then the event will simply go to the live view itself. There is no such thing as having a handle_event without live view at all, what would even be handling the event?

zoedsoupe

zoedsoupe OP

I mean: for a new phoenix project we have:

./lib/pescarte_web/
├── controllers
│   ├── app
│   │   └── researcher_controller.ex
│   ├── landing_controller.ex
│   └── login_controller.ex
├── layouts
│   ├── app.html.heex
│   └── root.html.heex
├── layouts.ex
└── templates
    ├── app
    │   ├── profile_html.ex
    │   └── researcher_html
    ├── error_html
    │   └── 404.html.heex
    ├── error_html.ex
    ├── landing_html
    │   └── show.html.heex
    ├── landing_html.ex
    └── login_html.ex

simplified. Then, those landing_html.ex files aren’t live views, are templates that can use components, but they do not handle events, right?

Example, here’s my login_html.ex file:

defmodule PescarteWeb.LoginHTML do
  use PescarteWeb, :html

  def show(assigns) do
    assigns = Map.put(assigns, :form, to_form(%{}, as: :user))

    ~H"""
    <main class="fish-bg h-full">
      <.simple_form for={@form} action={~p"/acessar"} class="login-form">
        <.text size="h3" color="text-black-80">
          Faça login para acessar a plataforma
        </.text>

        <fieldset class="login-fieldset">
          <.text_input field={@form[:cpf]} type="text" mask="999.999.999-99" label="CPF" required />
        </fieldset>

        <fieldset class="login-fieldset">
          <.text_input field={@form[:password]} type="password" label="Senha" required />
        </fieldset>

        <:actions>
          <div class="flex justify-between items-center">
            <.checkbox field={@form[:remember_me]} label="Mantanha-me conectado" id="remember" />

            <DesignSystem.link href={~p"/usuarios/recuperar_senha"} class="text-sm font-semibold">
              <.text size="sm">Esqueceu sua senha?</.text>
            </DesignSystem.link>
          </div>
        </:actions>

        <:actions>
          <.button style="primary" submit>
            <.text size="lg">Acessar</.text>
          </.button>
        </:actions>
      </.simple_form>
    </main>
    """
  end
end

This is not a live view, so cannot handle event and therefore does not define @myself. Am I wrong? To define a live view I need to use Phoenix.LiveView then implement mount/3 and handle_event/3

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hey @zoedsoupe you’re absolutely right, it’s only very recently that Phoenix started using heex for controllers and I basically totally forgot it does that now!

So back to your question: Yea you can only do handle_event and phx-target stuff on components used in a live view. If you do need to use a functional component between both live and traditional views you could probably pass in myself: nil as an assign, but also the button won’t really work.

zoedsoupe

zoedsoupe OP

Thanks for confirming this conception! there’s any part of the official documentation that explain this difference explicitly? I think the most important part is to understand that function components will not work with events on controllers templates.

For now i don’t need a component to trigger events on controller templates, a form action here is to save the session, so it can be safely a submit button to another route.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Not in the way you’re looking for that I see. That said if you read Components and HEEx — Phoenix v1.8.8 and the other docs it links to, you’ll notice that the word event never even appears. It’s only when you get to the live view docs do you start seeing events and handle_event.

— All posts loaded —

Where Next? Top

Trending in Questions Top

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
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
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
psy-q
I’m trying to set up Emacs with elixir-ls via lsp-mode and credo via Flycheck. This should mostly be preconfigured as Flycheck picks up c...
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
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
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
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

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews