`phx-click` and JS `onclick` together

Okay! Yes! This led me to a solution that works.

There are a few things that I think cause some confusion, both from the nomenclature and the lack of documentation.

First of all, be mindful of the difference between dispatchEvent(new Event("click", {bubbles: true})) and pushEvent('yourhandler', {foo: "bar"}. dispatchEvent is for in-DOM events, like button clicks, and pushEvent is for events that Phoenix will handle.

The second thing is that you will need to use a combination of both events to make this work.

So, here’s everything you need to submit a Phoenix event from interaction-free JavaScript.

First, define a hook in your app.js like so:

let Hooks = {}
Hooks.EventSender = {
    mounted() {
        this.el.addEventListener("eventSender", e => {
            this.pushEvent("your_phx_event", {foo: "bar"})
        })
    }
}
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks, params: {_csrf_token: csrfToken}})
liveSocket.connect()

Include that Hook on your template somewhere with a unique identifier:

<div id="sender_hook" phx-hook="EventSender"></div>

Then, to call it, send the DOM event in your JavaScript, which will be received by the hook, using the ID of the div you bound the hook to:

document.getElementById("sender_hook").dispatchEvent(new Event('eventSender'));

And this will send {foo: 'bar'} back to your your_phx_event handler on your server. Finally, note that if you are using this to have two ways of sending your phx events, one programmatic and one manual, you may need to use attributes or class membership as state to prevent recursion.

Thanks for the help, @malloryerik. I hope this helps anybody who finds it. (I also think the bit about using the Hook-bound object to send the event isn’t included in the documentation and probably should be.)

3 Likes