silverdr

silverdr

Sending events from JS to LiveView component

I know I can have heex attributes like phx-click="eventid" in the markup and then

def handle_event("eventid", _, socket), do: [...]

But how does one send that event without actually interacting? There are some examples in the guides like:

yet they seem to cover different cases:

  • handle custom client-side JavaScript when an element is added, updated, or removed by the server
  • Triggering phx- form events with JavaScript

but what I need is best described as “triggering arbitrary event that can be handled with handle_event/3 with JavaScript”. I found something similar here:

yet it’s been some time and many Phoenix changes since that fine piece was written.

How would you approach this task today?

Most Liked

cblavier

cblavier

You need a hook attached to the live_component that will receive the events. This hook will be initialized on mount.

defmodule MyLiveComponent do
  def render(assigns) do
    ~H"""
    <div phx-hook="MyLiveComponentHook">
       ...
    </div>
    """
  end

  def handle_event("custom-event", _params, socket) do
    {:noreply, socket}
  end
end

Then in your hook, listen for custom JS events and propagate them to your LiveComponent.

export const MyLiveComponentHook = {
  mounted() {
    window.addEventListener("my-app:custom-event", => {
      this.pushEvent("custom-event", {})
    });
  }
}

You can now trigger JS events from wherever you want, they will be handled by the hook and propagated to your LiveComponent

const event = new Event('my-app:custom-event');
window.dispatchEvent(event);

I just wrote this code directly on the forum, I hope this is kind of working :man_shrugging:

LostKobrakai

LostKobrakai

One can also look at @cblavier’s answer from the bottom up.

You have something happening somewhere in your JS (your callback) and want it to notify a LV or LiveComponent. How would you tell whatever API you call where things should be routed to? There’s no module names or fixed IDs you could hardcode there. Your LV or component might even be present multiple times on the current page. So your best best is some form of PubSub, where producers of data don’t need to know consumers upfront. That’s the dispatchEvent part.

Now how do you consume those dispatched events in a way that the can be forwarded to your LV pieces/server. That’s where hooks come in. They connect some JS with a section of markup, which LV knows how to connect to things on the server. Hooks do receive LV lifecycle events that’s true, but that doesn’t mean all they do needs to be based on lifecycle events. You can also listen for any other things happening and react to those as well. That’s the addEventListener part.

So now the hook receives events. Then you can use pushEvent to push data forward to the server to handle in an handle_event callback.

silverdr

silverdr

Other than two small typos (missing set of empty parens and “addEventListeRner”) it does :smiley: thank you!

Yes, that’s a very good explanation, thank you!

What I think I was hoping for was something like for example phx-js="eventid" (form/syntax aside) and the rest would be already set, similar to how e. g. phx-click= and Co. is working but the way you explained it is fine too. I should probably push a PR updating the docs so that it is clear that not only “form events” and “lifecycle events” are effortlessly handled this way.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New

Other popular topics Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29703 241
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39523 209
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement