What is the best way to assign multiple event handlers to Solid.js components within a single HTML element?

Introduction

I am currently exploring Solid.js and facing a challenge in adding multiple event handlers to the same HTML element from different components using JSX. While it's straightforward in Vue, I have noticed that Solid.js overrides events based on how they are added. I have demonstrated this behavior in both frameworks in an example which you can access here. In Vue, adding multiple event handlers works as expected, but in Solid, any additional event handler seems to override the previous one for a single event.

If you want to compare behaviors, you can toggle between useDivAsComponent in Solid and useDivAsComponent in Vue. Vue consistently handles multiple event handlers attached to a component or HTML element, while Solid's behavior varies depending on where events are added - either to an HTML element or another component.

My question is whether there is a simple way to attach multiple event handlers to the same HTML element using different components defined with JSX in Solid?

Details

In a scenario where I need to add DOM event handlers to the root element of a component, I also want users of the component to be able to append their own DOM event handlers to it. If the root element is like

(props) => <div {...props} />
, only the internal event handlers within the component are effective (external ones will be overruled). This happens because Solid merges props, resulting in only the last event handler being retained instead of utilizing addEventListener.

However, if the component's root element is a standard <div />, Solid generates code in a way that preserves both sets of event handlers. The built code shows Solid using addEventListener(), which aligns with expectations.

Potential Solutions

To work around this issue, one approach could involve passing a reference to the inner component (

<InnerComponent ref={ref} />
) to the parent and manually adding event listeners to prevent additional events from getting overridden (ref.addEventListener(...)). Although effective, this method may not be as user-friendly compared to other frameworks.

Alternatively, ensuring that the inner component where event handlers are applied is a regular <div /> may prompt Solid's compiler to generate code that incorporates event listeners instead of merging (and replacing) event handler props.

I am eager to discover a more seamless way to include multiple events in JSX, if feasible.

Answer №1

If you're looking to prevent overwriting events in Solid-js, consider using onmouseleave (in lowercase). This approach will not overwrite existing events but instead "sum" them together since Solid-js interprets lowercase as adding a new event listener. You can find more information about this discussion Here.

In your solid-js example, the implementation would look something like this:

import { render } from 'solid-js/web';
import { Component, JSX } from "solid-js"
type HtmlProps = JSX.HTMLAttributes<HTMLDivElement>

const useDivAsComponent = true

const ComponentInner: Component<HtmlProps> = (props) => {
  const log = (name: string) => console.log("inner", name)
  const Div = (p: HtmlProps) => <div {...p} />
  return useDivAsComponent
     // onmouseenter, onmouseleave, instead of onMouseLeave onMouseEnter
    ? <Div {...props} onmouseenter={[log, "enter"]} onmouseleave={[log, "leave"]} />
    : <div {...props} onmouseenter={[log, "enter"]} onmouseleave={[log, "leave"]} />
}

const ComponentOuter: Component<HtmlProps> = (p) => {
  const log = (name: string) => console.log("outer", name)
  return <ComponentInner {...p} onMouseEnter={[log, "enter"]} onMouseLeave={[log, "leave"]} />
}

const style: JSX.CSSProperties = { background: "lightgrey", width: "100%", height: "100vh" }
render(
  () => <ComponentOuter style={style} class='hola'></ComponentOuter>,
  document.getElementById('app') as HTMLElement
)

This modification should address your concerns. Best of luck!

Answer №2

In the Solid framework, there are several methods for adding event listeners. Event listeners added as a prop, like onClick, are delegated, meaning they are attached to the document node for improved performance. For non-delegated handlers, you can use the syntax on:{eventName}.

If you need to add a listener to an element within another component, using refs is recommended. This marks the third method, in which you can utilize addEventListener.

The approach you are currently employing is not optimal. A better strategy would be to have a single, delegated listener on a common ancestor, and then use conditionals inside the handler's body.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How is it possible for this for loop to function properly without the need to pass the incrementing variable

I managed to compile my code and it's working fine, but there's something interesting - the variable that should reference the incrementing value is not included as an argument in the for loop. var _loop2 = function _loop2() { var p = docume ...

Is There a Quicker Alternative to Eval for Generating Deep Clones?

I am looking to create deep clones of a very large object called veryBigObject. To initialize veryBigObject, it first needs to be initialized using the initVeryBigObject function. Here is how this process looks: initVeryBigObject = function(){ veryBig ...

Tips for navigating the material ui Expanded attribute within the Expansion Panel

After looking at the image provided through this link: https://i.stack.imgur.com/kvELU.png I was faced with the task of making the expansion panel, specifically when it is active, take up 100% of its current Div space. While setting height: 100% did achi ...

Troubles encountered with the search bar filter functionality, implementing JS/JQuery within a Laravel blade template

Currently, I have a blade template containing a search bar for filtering purposes. The issue I'm encountering is that the filtering functionality doesn't seem to work as expected after removing Angular from the page entirely. The page is set up ...

What is the best method for obtaining a modified image (img) source (src) on the server side?

Having some trouble with a concept in ASP.Net that's causing me quite the headache. I am fairly new to ASP.Net and struggling with something that seems much easier in PHP. I created an img element with an empty src attribute : <img runat="server" ...

PhantomJs is only providing partial responses

I have been attempting to retrieve a response from the following URL using PhantomJS:- https://www.trivago.com/api/v1/bin/accommodation/2891353/deals?iPathId=34812&iRoomType=1&aRooms=&aDateRange%5Barr%5D=2017-05-24&aDateRange%5Bdep%5D=2017 ...

Is there a way to ensure that the 'pointermove' event continues to trigger even after the dialog element has been closed?

I am working on a project that involves allowing users to drag elements from a modal dialog and drop them onto the page. I have implemented a feature where dialog.close() is called once the user starts dragging. This functionality works perfectly on deskto ...

Retrieve the CSS class definition using the console in the Chrome Developer Tools

Is there a way to automatedly extract CSS class definitions from Chrome Developer Tools? I want to retrieve the styles defined in a specific class name, similar to how it is displayed in the Styles tab on the right-hand side. I know about the getComputedS ...

Add a click event listener to the body element using a button click, without causing it to trigger

What is the current situation: A button is clicked by the user The menu opens (list items display = block) The function to close the menu is connected to the <body> The function to close the menu is immediately triggered, causing the menu to close ...

Using JavaScript to organize and categorize data within an array

I am working with a multidimensional array and need to filter it based on the value at a specific index position. Here is what the array looks like: arr = [ [1 , 101 , 'New post ', 0], [2, 101 , 'New Post' , 1], ...

gmap3 has encountered an error: undefined is not a valid function

I am working on a WordPress site and trying to integrate a Google map into the contact page. However, I'm encountering an error Uncaught TypeError: undefined is not a function in the JavaScript console. Below is the code snippet causing the issue, can ...

Leveraging the withWidth higher order component (HOC) provided by

I am currently using version 3.9.2 of Material UI and experimenting with the withWidth HOC in a server-side rendered application. When I disable Javascript in the debugger options of Chrome Developer Tools, everything functions as expected by displaying t ...

Guide on validating an email through a 6-digit code using Flutter, Node.js, and MongoDB

My goal is to create a registration process where users enter their email and password on a screen. After clicking "register", they should receive an email with a random 6-digit code for verification on the next page. I have everything set up, but I' ...

Issues with the HTML required attribute not functioning properly are encountered within the form when it is

I am encountering an issue with my modal form. When I click the button that has onclick="regpatient()", the required field validation works, but in the console, it shows that the data was submitted via POST due to my onclick function. How can I resolve thi ...

button that takes you back to the top of a mobile website

I want to customize the Scroll To Top button so that it only appears once the user begins scrolling down, rather than always being visible even when at the top of the page. Just a heads up, I don't have much experience with JavaScript, so I might need ...

Is it really necessary to still think poorly of JavaScript in 2011?

Here's an intriguing question for you. I've tested out a variety of popular websites, including Facebook, and I've noticed that many features still work perfectly fine even when JavaScript is disabled. People always used to say that JavaScr ...

Leverage multiple services within a single AngularJS controller

Is it possible to use multiple services in the same controller? Currently, I am able to achieve this with different services, but it seems to only perform one service. <!DOCTYPE html> <html> <script src="http://ajax.googleapis.com/ajax/libs ...

Is there a way for me to duplicate a complex element multiple times within the same page?

As an illustration, let's say I have a social tab located in my header that I would like to duplicate in the footer. This tab is comprised of various buttons with SVG images on top, event listeners linked to button IDs, and CSS styling. One option is ...

Attempting to use vue-test-utils-getting-started with the standard configuration results in a "Preset Not Found" error during

Currently, I am in the process of conducting a unit test by referring to the official guide provided. To do so, I have cloned the demonstration repository named vue-test-utils-getting-started. To replicate the issue, follow these steps: After cloning vu ...

Is there a way to modify the Javascript for this Contact Form to trigger a different action if a specific key is pressed instead?

I have been working on a Contact Form that integrates Google Scripts. Everything seems to be functioning well as it successfully sends emails and formats them properly in my inbox. However, there are two issues that I am encountering: -I want to exclude t ...