How to bind events dynamically in Svelte?

Viewed 2283

In JSX it's possible to bind multiple events to a DOM element like this:

<input {...inputEvents}>

In Svelte, this is done manually.

<input on:input={inputHandler}>

This becomes tedious when you need to add multiple handlers (input, blur, focus) to multiple inputs of a form.

The only way I've found to solve this in Svelte is by using refs.

For example:

<input bind:this={myInput}>

And then somewhere either do this:

myInput.oninput = (event) => {
  // do something
}

Or:

myInput.addEventListener('click', (event) => {
  // do something
})

Is there a better way to bind events dynamically in Svelte?

2 Answers

If you need to attach the same or similar set of event handlers to various elements then you can use "actions" with use:action (ref: https://svelte.dev/docs#template-syntax-element-directives-use-action )

Here is an example:

<script>
  function manyHandlers(element){
    element.addEventListener("click", ev => {...})
    element.addEventListener("focus", ev => {...})
    element.addEventListener("blur", ev => {...})
    ...
  }
</script>

<form>
  <input use:manyHandlers>
  <textarea use:manyHandlers></textarea>
  <!-- and so on... -->
</form>

You can pass additional parameters to the function specified in the use:___, for example to control which set of event handlers get attached. See the above mentioned documentation reference on how that works.

Also, as mentioned in the comments, you can take advantage of event bubbling and attach the event handler to a parent element (eg: the <form> element in the above example) and use the event.target to do specific handlings with the element that received the event.

You can use $: before the input handler.

<script>
    let myInput = "";

    $: {
        // Do something with myInput
    }
</script>

<body>
    <input type="text" bind:value={myInput}>
</body>

It's important to use the "myInput" variable in the eventHandler because it reacts to the state of the variables, used in the function. Also you should bind "value" not "this".

Related