admin管理员组

文章数量:1304137

I am looking for a way to listen to a dispatched event from a Svelte ponent within another ponent from JavaScript (and not from the on: syntax).

Here is the code I am trying to achieve on REPL.

The expected behaviour would be to have 0 displayed in the console when the button Close 0 is clicked, and so on for the other ones.

I am looking for a way to listen to a dispatched event from a Svelte ponent within another ponent from JavaScript (and not from the on: syntax).

Here is the code I am trying to achieve on REPL.

The expected behaviour would be to have 0 displayed in the console when the button Close 0 is clicked, and so on for the other ones.

Share Improve this question edited Jan 30, 2021 at 4:06 mantis 2151 gold badge4 silver badges17 bronze badges asked Apr 27, 2020 at 15:36 mlbichemlbiche 971 gold badge3 silver badges9 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

I went through some digging in svelte's piled code, and I found a solution to listen on svelte's handled event, but it's not pretty :)

You can (and should) dispatch your own custom event when calling onClose, but here's the solution:

on Nested.svelte

<script context="module">
    let counter = 0
</script>

<script>
    import { createEventDispatcher, onMount } from 'svelte';
    // add this
    import { get_current_ponent } from 'svelte/internal'; 
    let _this;
    const id = counter++
  const dispatch = createEventDispatcher()
    /*********
     and add this reactive statement
    **********/
    $: {
        if (_this){
            _this.parentNode.hosts = (_this.parentNode.hosts || []);
            _this.parentNode.hosts.push(get_current_ponent());
        }
    } 
    /*********
     end
    **********/
    function onClose() {
        dispatch('close', id)
    }
</script>
<!-- bind this -->
<button bind:this={_this} class='nested-button' on:click={onClose}>
    Close {id}
</button>

Then in your App.svelte

<script>
    import { onMount } from 'svelte'
    import Nested from './Nested.svelte'

    let element

    onMount(() => {
        // requestAnimationFrame is required!
        requestAnimationFrame(() => element.hosts.forEach(nestedButton => {
        nestedButton.$on('close', (e) => {
                console.log(e.detail)
            })
        }));
    })
</script>

<ul bind:this={element}>
    <Nested/>
    <Nested  />
    <Nested />
</ul>

Explanation -

the only way to bind to a svelte event is by getting a reference to the calling ponent and calling the $on method, but currently there's no easy way of getting a ponent's reference.

so what I did was calling the svelte's internal get_current_ponent, which will return the current ponent (but for some reason won't work when called inside onMount).

I appended the reference to the parentNode.hosts of the top most element in the ponent, which in this case is the ul element.

then you can just call the $on method for each reference in element.hosts.

The appropriate solution however will be dispatching you own event like this:

function onClose() {
        dispatch('close', id)
        this.dispatchEvent(new CustomEvent('close', {detail: id}));
    }

And by that achieving almost the exact same thing without messing with svelte's internals

I make use of svelte stores and reactivity:

signals.js:

import { writable } from 'svelte/store';
export const endSignal = writable({});

Sender.svelte:

<script>
import { endSignal } from './signals.js';
const signal = $endSignal;

function handleEndSignal(){
  // do other stuff, then send signal
  endSignal.update(()=> signal);
}
</script>

<button on:click={handleEndSignal}>The End</button>

Receiver.svelte:

<script>
import { endSignal } from './signals.js';

$: endItAll(), $endSignal;

let countEnds = 0;

function endItAll(){
  countEnds +=1;
}
</script>

<p>times end signal received: {countEnds}</p>

Basically, every time we click the button in Sender.svelte, the value "endSignal" in "signals.js" is overwritten, hence in Receiver.svelte the updated variable in the "$:" statement triggers the function "endItAll()".

本文标签: javascriptListening to a dispatched event from a Svelte componentStack Overflow