I am using LiveView to render a form and a
phx_change
event to send updates back to the controller. I’m also using an extra library (Select2:
https://select2.org/
) as a more robust
select
field control for a select input on the form. I have a JavaScript event listener tied to the Select2’s change event so that I can perform certain actions, and I’d like in my event listener to then be able to push the
phx_change
event back to the LiveView.
I’ve inspected the change event payload and noted it’s like any other event and just contains an encoded chunk of the full form data, so I can replicate that behavior in my own code if need be, but ideally I’d like a LiveView JS-interop way to do this programmatically. Something either like
this.pushFormChange()
or finding the form instance and making a
trigger
call on the event that the JS interop has bound to, but so far I’ve been unable to find anything either in the documentation, in the source code, or in some trial-and-error that works the way I want.
Is this something that’s possible or that anybody has done? Alternatively, is my approach simply wrong here?
via a hook on the input tag:
To trigger a phx-change:
this.el.dispatchEvent(new Event("input", {bubbles: true}))
To trigger a phx-submit:
this.el.dispatchEvent(new Event("submit", {bubbles: true}))
I’m trying to do the same but I’m running into a very pesky error where the hook dispatches the event just fine but LiveView appears to be crashing for some other reason. I am having a hard time debugging since this seems to be in the guts of LV.
Any help would be appreciated – I realize this is not much to go off of but maybe someone has experienced the same. Thank you!
Uncaught TypeError: Cannot read property 'querySelectorAll' of null
at Object.all (phoenix_live_view.js:1716)
at Object.showError (phoenix_live_view.js:1868)
at eval (phoenix_live_view.js:2845)
at Object.eval [as callback] (phoenix_live_view.js:2702)
at eval (phoenix.js:232)
at Array.forEach (<anonymous>)
at e.value (phoenix.js:231)
at Object.eval [as callback] (phoenix.js:250)
at e.value (phoenix.js:405)
at Object.eval [as callback] (phoenix.js:292)
I had to use this function one for input with phx-debounce="blur"
function fireInputChangeEvent(input) {
input.dispatchEvent(new Event("input", { bubbles: true }));
if (input.phxPrivate && input.phxPrivate["debounce-blur"]) {
setTimeout(() => input.dispatchEvent(new Event("blur", { bubbles: true })));
To be sure, basically phx-change
on form element has behaviour that live_view is listening to all of these events: onchange
, oninput
, onblur
inside given form element.
Is there some way to recognize which event triggered the phx-change (input,change or blur) ? I mean in live_view handle_event("phx-change-event")
thanks
This works well in Webkit and Chromium-based browsers, but I’m striking an issue with Firefox: Firefox insists on submitting the form over HTTP when I dispatch a submit
event to the form. This is the code (using AlpineJS, I’m attempting to submit the popover form when the user clicks away):
<%= f = form_for @changeset, "#",
id: "my_form",
phx_submit: "submit",
phx_target: @phx_target,
phx_trigger_action: false,
"x-data": "{show_form: true}",
"x-show": "show_form",
# Submit the form when we click off, and hide the popover
"x-on:mousedown.outside": "show_form = false; $el.dispatchEvent(new Event('submit', {bubbles: true}))" %>
Anyone know how to prevent Firefox from actually submitting over HTTP?
How would I trigger a form phx_submit
from a global hotkey?
IE ctrl + s
anywhere on the page would trigger it via window.onkeydown
.
Also reading the javascript interop docs, it looks like you add client side JS in app.js
, which is loaded for every page? Why can’t you inline the JS into your specific view?