Reputation: 261
I created a button in solid-js
and I would like that when this button is clicked, a page is opened and the counter goes to zero. To perform these operations, I have already created two functions. I would like to ensure that when clicking this button that these two functions are called asynchronously. So I wrote the following code:
<button
onClick={[toggle, setNullCount]}
>
with functions to call toggle
and setNullCount
. However, I realized that when I click on the button, only the first declared function is called and I don't know how to allow two functions to be called on click.
Upvotes: 0
Views: 1715
Reputation: 13698
A wrapper function is not equivalent to adding multiple listeners and it is not always feasible, i.e when you want to handle each events differently.
An alternative could be adding listeners to the element using its reference:
import { onCleanup, onMount } from 'solid-js';
import { render } from 'solid-js/web'
const App = () => {
let el: HTMLButtonElement | undefined;
const handleOne = (event: any) => {
console.log(`Event One`);
};
const handleTwo = (event: any) => {
console.log(`Event Two`);
};
onMount(() => {
el?.addEventListener('click', handleOne);
el?.addEventListener('click', handleTwo);
});
onCleanup(() => {
el?.removeEventListener('click', handleOne);
el?.removeEventListener('click', handleTwo);
});
return (
<div>
<button ref={el}>Click</button>
</div>
)
};
render(App, document.body);
You can see the live demo: https://playground.solidjs.com/anonymous/86afc8e3-3574-40ed-88f7-2e5b467f6b9a
Element is guaranteed to exist inside onMount
and onCleanup
effects but I didn't want to suppress the type system by a non-null assertion so used optional chaining operator, ?
.
Another alternative could be event delegation:
import { onCleanup, onMount } from 'solid-js';
import { render } from 'solid-js/web'
const App = () => {
const handleOne = (event: any) => {
console.log(`Event One`);
};
const handleTwo = (event: any) => {
console.log(`Event Two`);
};
onMount(() => {
document.body.addEventListener('click', handleOne);
document.body.addEventListener('click', handleTwo);
});
onCleanup(() => {
document.body.removeEventListener('click', handleOne);
document.body.removeEventListener('click', handleTwo);
});
return (
<div>
<button>Click</button>
</div>
)
};
render(App, document.body);
Click the link to see the live demo: https://playground.solidjs.com/anonymous/434364d4-c467-427f-8709-3e10557e0b9e
A third alternative could be using so called on:weirdEvent
syntax:
import { render } from 'solid-js/web'
const App = () => {
const handleOne = (event: any) => {
console.log(`Event One`);
};
const handleTwo = (event: any) => {
console.log(`Event Two`);
};
return (
<div>
<button on:click={handleOne} on:click={handleTwo}>Click</button>
</div>
)
};
render(App, document.body);
For any other events, perhaps ones with unusual names, or ones you wish not to be delegated, there are the on namespace events. This attribute adds an event listener verbatim. https://www.solidjs.com/docs/latest/api#on___oncapture___
You can find the live demo: https://playground.solidjs.com/anonymous/30c32d5b-3185-45ab-987d-15f2bf9c8f98
A fourth alternative could be using a custom directive. A custom directive receives the element when the element gets created in the DOM. So, you can attach the listener on the element itself or use event delegation. I will go with the former one here:
import { Accessor, onCleanup } from 'solid-js';
import { render } from 'solid-js/web';
interface Handlers {
handlerOne: (event: MouseEvent) => void;
handlerTwo: (event: MouseEvent) => void;
}
export const multipleHandlers = (el: HTMLButtonElement, args: Accessor<Handlers>) => {
el.addEventListener("click", args().handlerOne);
el.addEventListener("click", args().handlerTwo);
onCleanup(() => el.removeEventListener("click", args().handlerOne));
onCleanup(() => el.removeEventListener("click", args().handlerTwo));
}
declare module "solid-js" {
namespace JSX {
interface Directives {
multipleHandlers: Handlers;
}
}
}
const App = () => {
const handlerOne = (event: any) => {
console.log(`Event One`);
};
const handlerTwo = (event: any) => {
console.log(`Event Two`);
};
return (
<div>
<button use:multipleHandlers={{ handlerOne, handlerTwo }}>Click</button>
</div>
)
}
render(App, document.body);
https://playground.solidjs.com/anonymous/d6cbfe71-d657-4749-9126-a5fc5984a334
Explicit being better than implicit, I advice you to use any of the above methods over a custom directive. Custom directives could be a good alternative only when you find yourself in need to add multiple listeners to the same element frequently.
Upvotes: 0
Reputation: 451
Here is a solution
onClick={() => {toggle(); setNullCount()}}
when you want assign more than one action to trigger you must create a function which handles methods that will be performed as effect.
Upvotes: 1
Reputation: 19573
You need to create a single handler function that calls both handlers:
<button
onClick={() => {
toggle();
setNullCount();
}}
>
Upvotes: 1