Vincenzo Lombino
Vincenzo Lombino

Reputation: 251

Is it possible to make a child component inside a slot to send data to his parent?

I'm trying to create a Form component in Sveltejs. This Form component will use <slot /> to let his parent (App.svelte) define which Inputs and Buttons should be inside the Form. The Inputs and Buttons are components too and once the Input component's value changes I'd like to update an object inside the parent Form component and when Button is clicked I'd like to send data back to the App component.

I've tried to read Svelte documentation and solve this problem playing around with <slot let:name={value}> but I can't find a way to update Form component when an Input component's value changes.

This is the structure of what I'm trying to do:

App.svelte

...
<Form on:submit={saveReceivedData}>
  <Input name="..." value="..." />
  <Button />
</Form>
...

Form.svelte

<script>
...
let data = {}
</script>
...
<form>
  <slot />
</form>
...

Input.svelte

...
<input name={name} value={value} on:input={updateDataVariableOnFormComponent} />
...

Button.svelte

...
<button on:click={sendDataVariableToAppComponent}>Send</button>
...

I can try to send you a full code if needed. But, since my problem is not "what I'n doing wrong?" but "how can I do this?", I prefer to write my question in an abstract way.

Upvotes: 10

Views: 4175

Answers (2)

Vincenzo Lombino
Vincenzo Lombino

Reputation: 251

This is what I wanted to do. I'm honestly not 100% happy about it, but I'm loving Svelte :D

App.svelte

<script>
    import Form from "./Form.svelte"
    import Input from "./Input.svelte"
    import Button from "./Button.svelte"
    let data = {
        name: "John",
        surname: "Smith"
    }
    const saveValues = (event) => {
        data = event.detail
    }
</script>

<Form data={data} let:saveMe let:updateMe on:save={saveValues}>
    <Input
        label="Name"
        name="name"
        value={data.name}
        on:input={updateMe}
    />
    <Input
        label="Surname"
        name="surname"
        value={data.surname}
        on:input={updateMe}
    />
    <Button on:click={saveMe}>
        Save
    </Button>
</Form>

<h4>Saved data</h4>
<ul>
    {#each Object.entries(data) as d}
        <li>{d[0]}: {d[1]}</li>
    {/each}
</ul>

Form.svelte

<script>
    import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();
    export let data;
    const saveMe = () => dispatch('save', data)
    const updateMe = (e) => data = {...data, [e.detail.name]: [e.detail.value]}
</script>

<slot saveMe={saveMe} updateMe={updateMe} />

Input.svelte

<script>
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();
  export let name;
  export let label = false;
    export let value = "";
</script>

<div class="input-field">
  <input
    id={name}
    name={name}
    value={value}
        on:input={(e) => {
      value = e.target.value
      dispatch('input', e.target)
    }}
  />
  {#if label}
    <label
      for={name}
      class:active={value.length > 0}
    >{label}</label>
  {/if}
  <slot />
</div>

Button.svelte

<button on:click>
    <slot />
</button>

Upvotes: 0

Rich Harris
Rich Harris

Reputation: 29605

You can use a component binding to update data in the parent when the child component changes:

<Input name="..." bind:value={someValue} />

With that binding, someValue in the parent will be synced to value in the child.

To notify the parent about events in the child, as opposed to state changes, you can either use an event dispatcher...

<!-- Button.svelte -->
<script>
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();
</script>

<button on:click={() => dispatch('thinghappened', someData)}>Send</button>

...in which case you could listen for the thinghappened event...

<Button on:thinghappened={e => doSomethingWith(e)}/>

...or you can simply forward the DOM event with <button on:click>Send</button> and listen for the click event in the parent with <Button on:click={handler}/>.

Upvotes: 4

Related Questions