S
SolidJSsponge

Delegated custom events

Should delegated events work with custom events sent via HTMLElement dispatchEvent? The (new) docs mention:
For any other events, such as custom events or events you wish not to be delegated, the on: attribute will add an event listener as-is.
If you need to attach an event listener to an element that is not supported by Solid's event delegation, such as a custom event in a custom element, you can use the on:__ form.
I'm wanting to use delegated events so I can have a component that uses onMyEvent, and also allow users of that component to add their own onMyEvent on the same component. Even though the docs imply I need to use the on: form to attach a native event, the delegated events seem to work correctly. TS does complain about the JSX, though (I have setup the event in JSX.CustomEvents/CustomCaptureEvents): Property 'onMyEvent' does not exist on type 'HTMLAttributes<HTMLDivElement>'. Did you mean '"on:myevent"'? Should I be able to use delegated events for this custom event, and if I can, how do I get TS to stop complaining about that property not existing?
D
Dsaquel17d ago
If you need to attach an event listener to an element that is not supported by Solid's event delegation, such as a custom event in a custom element, you can use the on:__ form.
delegated events works only with solid's event delegation. Now for your custom event you need to type your own event: https://docs.solidjs.com/configuration/typescript#advanced-jsx-attributes-and-directives
S
Sarguel17d ago
Hello, you can see event delegation order illustrated with this example: https://playground.solidjs.com/anonymous/f57f8222-23e3-4472-8573-205f6e5c0a29 To answer your question the custom event foo in the example also work with the solid delegation form ( without : ) but if you go and see in the output tab you will see that solid compile it to a dom listener event instead of the solid delegated event primitive
_el$.addEventListener("foo", () => console.log("HELLO FOO from SOLID ??"));
#instead of
_el$.$$foo = () => console.log("HELLO FOO from SOLID ??");
_el$.addEventListener("foo", () => console.log("HELLO FOO from SOLID ??"));
#instead of
_el$.$$foo = () => console.log("HELLO FOO from SOLID ??");
I suspect that if the event doesn't get recognized it get transformed to a delegate event. I don't know if this is a documented behaviour or even if it is by design. We would need someone that know better. In the meantime I would advise you to use the on: form
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
S
Sarguel17d ago
maybe relevant code from dom-expression:
} else if (prop.slice(0, 3) === "on:") {
const e = prop.slice(3);
prev && node.removeEventListener(e, prev);
value && node.addEventListener(e, value);
} else if (prop.slice(0, 10) === "oncapture:") {
const e = prop.slice(10);
prev && node.removeEventListener(e, prev, true);
value && node.addEventListener(e, value, true);
} else if (prop.slice(0, 2) === "on") {
const name = prop.slice(2).toLowerCase();
const delegate = DelegatedEvents.has(name); // <------------
if (!delegate && prev) {
const h = Array.isArray(prev) ? prev[0] : prev;
node.removeEventListener(name, h);
}
if (delegate || value) {
addEventListener(node, name, value, delegate); // <-------------
delegate && delegateEvents([name]);
}
} else if (prop.slice(0, 3) === "on:") {
const e = prop.slice(3);
prev && node.removeEventListener(e, prev);
value && node.addEventListener(e, value);
} else if (prop.slice(0, 10) === "oncapture:") {
const e = prop.slice(10);
prev && node.removeEventListener(e, prev, true);
value && node.addEventListener(e, value, true);
} else if (prop.slice(0, 2) === "on") {
const name = prop.slice(2).toLowerCase();
const delegate = DelegatedEvents.has(name); // <------------
if (!delegate && prev) {
const h = Array.isArray(prev) ? prev[0] : prev;
node.removeEventListener(name, h);
}
if (delegate || value) {
addEventListener(node, name, value, delegate); // <-------------
delegate && delegateEvents([name]);
}
and
export function addEventListener(node, name, handler, delegate) {
if (delegate) { // <--------------------- false
if (Array.isArray(handler)) {
node[`$$${name}`] = handler[0];
node[`$$${name}Data`] = handler[1];
} else node[`$$${name}`] = handler;
} else if (Array.isArray(handler)) {
const handlerFn = handler[0];
node.addEventListener(name, (handler[0] = e => handlerFn.call(node, handler[1], e)));
} else node.addEventListener(name, handler); // <----------------------
}
export function addEventListener(node, name, handler, delegate) {
if (delegate) { // <--------------------- false
if (Array.isArray(handler)) {
node[`$$${name}`] = handler[0];
node[`$$${name}Data`] = handler[1];
} else node[`$$${name}`] = handler;
} else if (Array.isArray(handler)) {
const handlerFn = handler[0];
node.addEventListener(name, (handler[0] = e => handlerFn.call(node, handler[1], e)));
} else node.addEventListener(name, handler); // <----------------------
}
refs: - https://github.com/ryansolid/dom-expressions/blob/ae71a417aa13b33517082628aff09513629df8b2/packages/dom-expressions/src/client.js#L320-L338 - https://github.com/ryansolid/dom-expressions/blob/ae71a417aa13b33517082628aff09513629df8b2/packages/dom-expressions/src/client.js#L127-L137
GitHub
dom-expressions/packages/dom-expressions/src/client.js at ae71a417a...
A Fine-Grained Runtime for Performant DOM Rendering - ryansolid/dom-expressions
S
Sarguel17d ago
const delegate = DelegatedEvents.has(name);
const delegate = DelegatedEvents.has(name);
so if the DelegatedEvents doesn't has your custom event it won't delegate but just fallback to the addEventListener on the node. for final reference:
// list of Element events that will be delegated
const DelegatedEvents = /*#__PURE__*/ new Set([
"beforeinput",
"click",
"dblclick",
"contextmenu",
"focusin",
"focusout",
"input",
"keydown",
"keyup",
"mousedown",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"pointerdown",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"touchend",
"touchmove",
"touchstart"
]);
// list of Element events that will be delegated
const DelegatedEvents = /*#__PURE__*/ new Set([
"beforeinput",
"click",
"dblclick",
"contextmenu",
"focusin",
"focusout",
"input",
"keydown",
"keyup",
"mousedown",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"pointerdown",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"touchend",
"touchmove",
"touchstart"
]);
S
sponge16d ago
thanks for the input here! i ended up using onmount/oncleanup addeventlistener for the base component so the users of that component can use on:. but it seems like on without the colon should work it just won't be delegated
Want results from more Discord servers?
Add your server
More Posts
`createEffect` doesn't working in `input.addEventListener('change')`Here is source link: https://gitlab.com/ndt-challenge/dev.to/1st/-/blob/main/Glam%20Up%20My%20MarkupTypescript auto completion is broken in a monorepoHi, i've setup solidjs inside a mono-repo which has a react app as well. it seems my auto completioTernary and Show have unequal outputIn a basic Vite and Solid app, I have ```js const [page, setPage] = createSignal({ image: null, websocket get peers on the servercan you show an example of how to get websocket peers on the server solistartRouter isn't working.Why routing is not working when i'm following exactly what doc says. Doc: https://docs.solidjs.com/Idiomatic way to handle API route errorsHi folks, Consider the following API route, using Solid Start: ``` export async function GET() { "Cannot call server function outside of a request" in onRequest middlware hookThis doesn't happen all the time. But happens.What do you recommend for drag and drop capabilities?I am creating an app using tauri and solid for my frontend. And am wanting to have the ability to drAdding Auth to Solid-Start, need some pointersFirst, sorry, this might be a little more generic than just Solid, but I've created my Solid Start aRouter brakes cssCode that works: ```js ...(index.tsx) const root = document.getElementById('root'); if (import.metacreateShortcut callbacks fire even if a textinput has focusI'm making a todo app which has vim motions for navigation. When I hit 'j' or 'k' i'd like these keyRemoving element from store array doesn't remove rendered itemsHi, i need help with this. I have a store that is shared in a context with some helper functions. <Index> with storesHello there, I'm building an application where I have a store defined in a separate non-component fiCan't find replace attribute on <Navigate />This is basically my code, I am trying to check if the user is authenticated, if not then redirect t