Sending JavaScript CustomEvents from the liveview client to the server

I’m building my app with Phoenix Liveiew, but I want an interactive client-side LeafletJS map. Building the map as a WebComponent has been fine, and integrates well with my Phoenix templates. But I wasn’t sure how to get my CustomEvents from my web component to be sent to the server.

Then I found this really helpful blog post by Chris Nelson. Chris provides a plug-in hook to help out with forwarding custom events via LiveView, but he does note:

It’s worth pointing out that if LiveView adds support for Custom Events, the hook and the
library which contains it will no longer be needed.

The blog post was written October 2020. As a relative newcomer to Elixir and Phoenix, I’m not sure if anything has changed in that time. So just a quick sanity check really: do I still need to add the hook as described, or is there built-in support now?

You can now push JS events back to the server using pushEvent in a hook - it is documented here: JavaScript interoperability — Phoenix LiveView v0.18.0

Basically the pattern is to create the appropriate JS event handler in the hook mount, capture the events and send them to the server using pushEvent

An example for handling infinite scroll is described here:

Thanks @mindok, using my own hook I’ve got the map events flowing back to the server very nicely! And your ElixirCast example was indeed helpful :+1:

1 Like

Sorry for the necro-post.

I’m getting pushEvent is not a function on the client side.

# the pushEvent fails
window.addEventListener("phx:show_confirm", () => {
    if (confirm("Are you sure you want to perform this action?")) {
        this.pushEvent("confirm", {}) # w & w/o this still fails
      # User confirmed, perform the action
    } else {
      # User canceled
    }
  });

It needs to be called from within a client side hook.

<div id="infinite-scroll" phx-hook="InfiniteScroll" data-page={@page}>

Hooks.InfiniteScroll = {
  page() { return this.el.dataset.page },
  mounted(){
    this.pending = this.page()
    window.addEventListener("scroll", e => {
      if(this.pending == this.page() && scrollAt() > 90){
        this.pending = this.page() + 1
        this.pushEvent("load-more", {})
      }
    })
  },
  updated(){ this.pending = this.page() }
}