Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass data from child to parent with 2 Svelte components in HTML parent-child relationship

I'm new to Svelte. I have 2 Svelte components in an HTML parent-child relationship – as opposed to a Svelte P/C relationship (where 1 Svelte component imports another).

Ultimately, I want something like this (could have many Accs.):

  <Accordion header={--property from SvelteComponent-- }>
    <SvelteComponent />
  </Accordion>

I would like the SvelteComponent to define the header used in the Accordion (it can be dynamic). I can use stores for this but that seems too messy. Accordion does contain a slot but I can’t see how to pass information upward. Can anyone suggest a path forward?

like image 537
user49011 Avatar asked May 22 '20 16:05

user49011


People also ask

How do you pass value from child to parent component?

To pass data from child to parent component in React:Pass a function as a prop to the Child component. Call the function in the Child component and pass the data as arguments. Access the data in the function in the Parent .


2 Answers

One option is to use component bindings. This allows a two-way binding between a value in the scope of a container component and a prop of the contained component.

<Accordion {header}>
    <SvelteComponent bind:header={header} />
</Accordion>

and in SvelteComponent.svelte:

<script>
    export let header = "defaultHeader";
</script>

Whenever SvelteComponent makes a change to defaultHeader, it will propogate back up via the binding to the file which contains the Accordion and SvelteComponent, and apply the changes back downward. https://svelte.dev/tutorial/component-bindings

Alternatively, you can provide a setHeader function as a prop to SvelteComponent, which sets the value of header:

//SvelteComponent.svelte
<script>
    export let setHeader;
</script>

<div on:click={() => setHeader("myHeader")}>
    My Svelte Component
</div>
like image 173
skeletizzle Avatar answered Oct 29 '22 18:10

skeletizzle


Svelte is great at getting rid of boilerplate and unnecessary extra code. I want to take that as far as I can.

I believe using @skeletizzle answer that I would have to add a variable to the container of the Accordions, for each Accordion and its child. THAT is what I want to eliminate (it pollutes the namespace of the container for a trivial operation). Since the Accordion and its child are in a P/C relation - they know about each other and the compiler could make communication direct. Think of an implied interface where the Accordion looks in its child and it it finds a prop named, say 'header', automatically, reactively, uses that for its own header prop.

What I am going to do is use stores though as stated, I feel they are too heavy - but don't think I have an alternative.

WrappedComponent.svelte

<script context="module">
  import { writable } from 'svelte/store'
  export let thisComponentHeader = writable('default header')
</script>

App.svelte

import WrappedComponent, { thisComponentHeader } from './WrappedComponent.svelte'
...
<Accord header={$thisComponentHeader}>
  <WrappedComponent />
</Accord>

There still is a variable. but it is socked away in the import definition

One thing this prevents is having more than 1 instance of the component.

like image 43
user49011 Avatar answered Oct 29 '22 16:10

user49011