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
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 ![]()
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
Other than two small typos (missing set of empty parens and “addEventListeRner”) it does
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.
Popular in Questions
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
- #hex










