Skip to content

Svelte 5: Include event modifiers previously found pre svelte 5 as functions available from the svelte library #11458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JacobSilasBentley opened this issue May 4, 2024 · 4 comments

Comments

@JacobSilasBentley
Copy link

JacobSilasBentley commented May 4, 2024

Describe the problem

I would like for the functionality of event modifiers previously available before svelte 5 for example 'click', 'once' and 'preventDefault' (shown below) to be readily available in svelte 5.

<button on:click|once|preventDefault={handler}>...</button>

Describe the proposed solution

In the preview documentation it suggests creating functions to replace event modifiers.

So the following:

<button on:once|preventDefault={handler}>...</button>

would be rewritten as:

<button onclick={once(preventDefault(handler))}>...</button>

In my opinion, it would be nice if these functions were available from the svelte library itself rather than having to write them independently. This would bring parity between svelte 4 in and svelte 5 for this feature and help minimise work needed for migration.

I understand the addition of these functions needs to be considered against the trade-off of additional bloat to the library, especially as these are relatively quick and simple functions to write (though ensuring the typing is correct adds some difficulty in my experience).

I would be happy to put in a PR for the change if it is deemed a worthwhile addition.

Importance

nice to have

@yus-ham
Copy link
Contributor

yus-ham commented Jun 4, 2024

while agree to this, I'll share some ideas.

It don't have to be nested(wrapping(a(handler))), we can use chaining as previously instead

<button onclick={ callable(handler).once.preventDefault }>click me!</button>

It utilizes Proxy internally. here the preview

@stalkerg
Copy link
Contributor

stalkerg commented Oct 23, 2024

I agree; it should be done somehow. Keeping it in legacy with "deprecated" is also not really good.
Here https://svelte.dev/docs/svelte/v5-migration-guide#Event-changes-Event-modifiers, I disagree with the argument:

Adding things like event.preventDefault() inside the handler itself is preferable, since all the logic lives in one place rather than being split between handler and modifiers.

I think "business logic" and event process is a completely different case, instead:

<a href="" on:click|preventDefault={() => setPage(currentPage + 1)}>Next</a>

I need to do:

<a href="" onclick={(event) => { event.preventDefault(); setPage(currentPage + 1); }}>Next</a>

Or, in that case, I should create a new function on top of what I already have, like setPagePreventDefault.

@yus-ham I suppose it's a good proposal, but not so cool if you put an arrow function instead of just the handler name.

@inta
Copy link

inta commented Dec 11, 2024

I just tried to put the modifiers at the beginning and came up with this:

<a href="" onclick={event.preventDefault.once(() => {console.log('Hello world')})}>foobar</a>

This works in most cases, but not all. You cannot create passive/nonpassive modifiers this way.

You can find the code here.

@hyunbinseo
Copy link
Contributor

hyunbinseo commented Feb 10, 2025

Why is the once considered deprecated?

<script>
  // 'once' is deprecated.js(6385)
  import { once } from 'svelte/legacy';
</script>

<button
  onclick={once((e) => {
    e.preventDefault();
    handler(e);
  })}>...</button
>

Event the docs suggests making the once wrapper.

Since event handlers are just functions, you can create your own wrappers as necessary:

function once(fn) {
  return function (event) {
    if (fn) fn.call(this, event);
    fn = null;
  };
}

Note that this is different from the svelte/legacy implementation:

/**
 * Substitute for the `once` event modifier
 * @deprecated
 * @param {(event: Event, ...args: Array<unknown>) => void} fn
 * @returns {(event: Event, ...args: unknown[]) => void}
 */
export function once(fn) {
  var ran = false;

  return function (...args) {
    if (ran) return;
    ran = true;

    // @ts-ignore
    return fn?.apply(this, args);
  };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants