Skip to content
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

Make dispatched events cancelable, and be able to detect if an event was canceled inside the component #7659

Closed
coyotte508 opened this issue Jul 6, 2022 · 2 comments

Comments

@coyotte508
Copy link

coyotte508 commented Jul 6, 2022

Describe the problem

Similar to DOM events, I want to be able to cancel dispatched event.

An example is a Tabs component:

<Tabs bind:value={currentValue} entries={entries} />

This works well. The user can click a tab to switch tabs. But I may want to prevent that behavior:

  • When there's a loading state
  • I want to display a confirm popup, if changing the tabs changes a setting
  • I want to display a message that this feature is unavailable for current subscription tier
  • ....

Describe the proposed solution

It would be nice to be able to do:

<Tabs bind:value={currentValue} entries={entries} on:input={e => if (...) {e.preventDefault()}} />

And that the Tabs component can detect if the event was prevented:

const dispatch = createEventDispatcher<{"input": string}>({cancelable: true});

function onClickTab(key: string) {
  const event = dispatch("input", key);
  if (!event.defaultPrevented) {
    value = key;
  }
}

The change in svelte's source seems small in scale:

function custom_event(type, detail, opts) { // changed to add "opts"
    const e = document.createEvent('CustomEvent');
    e.initCustomEvent(type, false, !opts ? false : opts.cancelable === true, detail); // changed
    return e;
}

function createEventDispatcher(opts) { // changed to add "opts"
    const component = get_current_component();
    return (type, detail) => {
        const callbacks = component.$$.callbacks[type];
        if (callbacks) {
            // TODO are there situations where events could be dispatched
            // in a server (non-DOM) environment?
            const event = custom_event(type, detail, opts);  // changed
            callbacks.slice().forEach(fn => {
                fn.call(component, event);
            });
            return event; // added
        }
    };
}

Alternatives considered

The alternative for the Tabs component are:

  • to delegate the value switching to the parent component: Tabs only sends an event with the new value, it's up to the parent to change the prop passed to value.
  • use callbacks instead of events: a callback with a return value could be passed as a prop, and if the return value is false, the prop is not changed
  • adding an extra prop shouldChangeValue, and other ugly solutions

Importance

would make my life easier

@Prinzhorn
Copy link
Contributor

I might be missing something, but any chance you are on an outdated local Svelte branch? This is already possible #7064

https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md#3480

@coyotte508
Copy link
Author

Oh, thanks and sorry for the noise!

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

2 participants