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?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With