Yes.
You can stick the “JS commands” in an attribute then execute them separately via execJS
.
Eg, given the element:
<div
data-commands={JS.add_class("bg-red-500")}
data-on-event="mouseover">hover</div>
and something like:
const attachCustomEvent = (el) => {
// data-on-event could be mouseover, mouseout, etc
el.addEventListener(el.dataset.onEvent, ({ target }) => {
const commands = target.dataset.commands
if(commands){
liveSocket.execJS(target, commands)
}
})
}
You can attach to existing dom elements via:
// attach to all existing in document.
document.querySelectorAll("[data-on-event]").forEach(attachCustomEvent)
but you also need to hook new elements as they’re added:
let liveSocket = new LiveSocket("/live", Socket, {
params: {_csrf_token: csrfToken},
dom: {
// not 100% sure this is the best way, but its *a* way. It might even technically be
// a private method, just popped up in autocomplete, if its private use a hook as described below.
onNodeAdded(node) {
// Attach handler to new elements, this probably has a nicer way?
// Note this is called for text nodes too, so we want to explicitly check
// for HTMLElements.
if(node instanceof HTMLElement && node.dataset.onEvent){
attachCustomEvent(node)
}
return node
},
// onBeforeElUpdated(from, to) {
// // possibly also want to attach here sometimes.
// }
}
})
You can simplify this somewhat by having a “global [sic] view hook” that you
attach to your root element, and just use the updated
callback in there to
run the querySelectorAll
against the subtree, ask if that doesn’t make
sense. Probably that is more maintainable in the long run.
Never done the above in prod, so not 100% sure on how quirky onNodeAdded
is,
buyer beware.
This does rely on you serialising out a %JS{}
struct, as the “across the
wire” rep is technically an opaque type.
You could add more complications to this, like data-exec-on-mouseover={JS} data-exec-on-mouseout={JS}
and parse the event name from the data prop etc. You also don’t have to use data-*
attributes if you don’t want to but probably don’t call them phx-mouseover
.