You can also focus an input by using a LiveView push_event
if you need the server, or via the LiveView.JS push api without the server by adding JS.dispatch
to it. So these are just slightly different flows with slightly different use-cases from the hooks example that @ibarch posted.
From the Server
Push a JS event from a handle_event
or handle_input
function. You catch your pushed event in either app.js with a window.addEventListener
or in a LiveView hook, and then send your changes to the DOM from there.
So that’s something like:
- Start with an instigating event, for example a click.
<span phx-click="do_stuff_plus_focus_my_input" ...>Just click it</span>
- Handle it and send a push_event. I’ve called mine
focusElementById
and sent a little map with the id of the input I want to focus. That map becomes the value for the JavaScript event object’sdetail
key, as you’ll see in the third step.
def handle_event("do_stuff_plus_focus_my_input", %{"foo" => bar}, socket) do
socket = assign(socket, foo: bar)
{:noreply, push_event(socket, "focusElementById", %{id: "my-input"})}
end
- Now catch that pushed event either from a hook or, as here, from
app.js
. The id we included (“my-input”) is in the event object asevent.detail.id
. Then just use standard JS’.focus()
and you’re done.
# app.js
window.addEventListener(`phx:focusElementById`, (event) => {
document.getElementById(event.detail.id).focus()
})
Anyway the push_event
docs go over all of this and are probably better written than what I have here.
Client-only Version
I’ve also finally noticed that LiveView.JS
has a function called push that lets you compose events that you send from templates. We can use that with JS.dispatch to cut out the server.
-
JS.push
andJS.dispatch
in action.
# plz excuse the formatting...
<span phx-click={ JS.push("choose_part_of_speech")
|> JS.dispatch("phx:focusMe", to: "#my-input")
}>Click it good</span>
- We can grab that event with a
window.addEventListener
. This is almost the same as with the server, but we’re sending the id name as a string and not in a map, so our JavaScript event object in our listener now has our element ID undertarget
and notdetail
in a map. So we access the id withevent.target.id
. Just small differences that keep me in the docs and that I hope will be automated away… You’ll see below.
# app.js
window.addEventListener(`phx:focusMe`, (event) => {
document.getElementById(event.target.id).focus()
})
And that’s it. It’s all in the docs, but writing things out makes it easier for me to remember.