LiveView re-render on js event

Hi all,

I am using phx 1.5.9 and live view 1.15.1. I have a small live view embedded in an eex page (using live_render not a route) that is rendering a list of things. They have a delete button which has a phx-click to a live view event and this all works well, seamlessly re-rendering the view when a delete happens.

New items are created in vanilla js somewhere else using an API call, and there is also the event where an item is no longer eligible for the list, that also happens in some js code.

My question is - is it possible / easy to tell the live view from js code - “please re-render yourself, things are now different with regard to your props”? I have hung the liveSocket on document to be able to access it from the other js code, but I see no methods on it that can help me send some signal to the live view from that code.

You can attach a JS hook to your live view, and use the pushEvent method to send any event with any payload to your LiveView: JavaScript interoperability — Phoenix LiveView v0.20.2

So you could send this message to your LV from JS: “dear LiveView, please update your assigns in the following way”. Your LiveView can react to the event by implementing a handle_event/3 callback and update its assigns.

Ok great, I saw some stuff around that approach but wasn’t certain it was exactly what I was looking for. So then to call in to that from vanilla js I would just find the element the phx-hook is on (getElementById f.e.x) and then dispatchEvent to it?

Yes that would work, provided you have the proper event handler on your hook’s DOM element. Something like this (didn’t test it):

MyHook: {
  mounted() {
    this.el.addEventListener("event_from_vanilla_js", (event) => {
     this.pushEvent("event_for_liveview", some_payload)
   })
  }
}

// somewhere in JS land...

document.getElementById("dom_element_with_hook").dispatchEvent("event_from_vanilla_js")

Yes I got it working pretty much exactly like that except the dispatchEvent method takes an Event object rather than a string so

document.getElementById("dom_element_with_hook").dispatchEvent(new Event("event_from_vanilla_js"));

Thanks so much for this help :slight_smile:

1 Like