Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for component to be ready in custom svelte directive

I recently tried to write a custom directive that did some logic and dispatched an event back to the element it was used on.

//svelte file
<div use:customDiective on:success={handleSuccess}>...</div>
// Custom directive
export const customDirective = node => {
    //some synchronous logic here

    node.dispatchEvent(new CustomEvent('success', node))
}

What I found out is that since the logic in my directive is synchronous it will dispatch the new custom event before the node is ready to catch it. I was able to easily solve it by using setTimeout(), but that does not seem like a proper solution. Is there any way for me to use a lifecycle method or something in the directive to make sure the component is ready for the dispatched event?

like image 785
Mats Avatar asked Nov 26 '25 07:11

Mats


1 Answers

You can use the onMount lifecycle function inside your action:

// directive.js
import { onMount } from 'svelte';

export const customDirective = (node) => {
    onMount(() => {
        // other logic
        node.dispatchEvent(new CustomEvent('success', node));
    });     
}
<!-- App.svelte -->
<script>
    import { customDirective } from './directive.js';
    
    let isSuccess = false;
</script>

<div use:customDirective on:success={() => (isSuccess = true)}>{isSuccess}</div>

Alternatively, if you put the on: directive before the use: directive, the event listener will be set up before running the action.

<div on:success={() => (isSuccess = true)} use:customDirective>{isSuccess}</div>

You can see the order of directives in the generated Svelte code:

// on: before use:
if (!mounted) {
    dispose = [
        listen(div, "success", /*success_handler*/ ctx[1]),
        action_destroyer(customDirective_action = customDirective.call(null, div))
    ];

    mounted = true;
}

// use: before on:
if (!mounted) {
    dispose = [
        action_destroyer(customDirective_action = customDirective.call(null, div)),
        listen(div, "success", /*success_handler*/ ctx[1])
    ];

    mounted = true;
}
like image 63
Geoff Rich Avatar answered Nov 28 '25 22:11

Geoff Rich