Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passing data into yield blocks #687

Closed
Conduitry opened this issue Jul 2, 2017 · 9 comments
Closed

Passing data into yield blocks #687

Conduitry opened this issue Jul 2, 2017 · 9 comments

Comments

@Conduitry
Copy link
Member

I'm working on a little project that may or may not see the light of day, a router inspired by React Router v4. One thing I'm finding I wish Svelte could do is let me pass some data from the nesting component inside its contents, not just from the instantiating component to the contents. This is a little confusing to describe. An example:

App.html

<Outer>
  {{foo}}
</Outer>

<script>
  import Outer from './Outer.html'
  export default {
    components: { Outer },
  }
</script>

Outer.html

<div>
  <div>Something</div>
  {{yield}}
</div>

<script>
  export default {
    data: () => ({ foo: 'bar' }),
  }
</script>

The {{foo}} in App.html is undefined, because it's referring to foo in App.html. What I'm looking for is some way to get the value of foo that's in Outer.html into the yielded contents of the <Outer> component in App.html.

I think the data values that are passed in like this should definitely be explicitly mentioned. One thing I thought of, based on my idea of a <:Yield/> tag here, is to have a syntax like <:Yield foo='{{foo}}'/> instead of {{yield}}. What I'm not clear on, however, is if App.html also had a foo whether its foo or Outer.html's foo should take precedence.

I'm also not clear on whether this is something we'd want to have, or whether it's something that's practical to implement in Svelte currently. As far as I know, using a {{yield}} tag doesn't create another scope/context/state object, and everything inside <Outer> is just hooked up to the same state as everything outside it is. Implementing something like what I'm describing here would require creating a new state, one that's the result of merging two separate states. And then there'd be the question of what happens when someone calls this.set inside <Outer> ... which state is updated?

This could all turn out to be not worth the effort and complication! Thoughts welcome.

@PaulBGD
Copy link
Member

PaulBGD commented Jul 4, 2017

Any reason adding bind:foo to the <Outer/> element doesn't work for this case?: https://svelte.technology/repl?version=1.23.4&gist=ce14b1187c7e2c8a27332e77d226f0b8

@Conduitry
Copy link
Member Author

Hmm, not sure why I had entirely written off using bind:. Yeah that certainly covers this case, and it covers some of the other cases I'm working on as well. The main difference between the sort of thing I was suggesting and using bind:foo is that with bind:foo, {{foo}} will have a value even outside the <Outer> tag. That's not a concern here, but there are certainly situations where it would be. I don't know. We'll see whether my router's syntax ends up being too ugly to be usable :)

@Rich-Harris
Copy link
Member

Have to confess the idea of foo meaning different things in these two cases...

<Outer>
  {{foo}}
</Outer>

{{foo}}

...gives me the heebie-jeebies. Perhaps at that point we're better off settling on a way to pass components through as parameters?

<!-- App.html -->
<Outer contents={Inner}/>

<!-- Outer.html -->
<div>
  <div>Something</div>
  <[contents] foo='bar'/>
</div>

@Conduitry
Copy link
Member Author

Yeah, I can see foo being different things in different places being undesirable.

As for a way to pass components through parameters ... I'd actually already come up with a sorta-acceptable way to do that as part of my routing library experiment: Have a <div ref:whatever/> in the component, and pass in the component class as data, and manually instantiate and mount the component. (Very WIP-y code.) But some sort of official way to do that in the language would make this nicer - and would mean I would have to worry less about destroying components when their parent is destroyed, which I'm certainly not being vigilant about in my code.

Also, there's definitely a possibility of an XY problem here - that I have been thinking too narrowly and trying to follow React Router's API, and haven't put in enough time thinking about a more Svelte-friendly way to achieve these broader goals.

@PaulBGD
Copy link
Member

PaulBGD commented Jul 5, 2017

I could see having a built-in way to pass a component though, because currently it's definitely possible from the user side but it requires some boilerplate code that we could move to svelte.

@TehShrike
Copy link
Member

I would love an in-language way to pass components through parameters.

I would hope for it to come with React-like behavior where I could pass in a string (like div or a) and have it show up as a normal div/a element when the child component used it.

@Rich-Harris
Copy link
Member

I would hope for it to come with React-like behavior where I could pass in a string (like div or a) and have it show up as a normal div/a element when the child component used it.

Not sure I follow, can you elaborate? Want to be sure we're on the same page. Though we should probably discuss that on #640 (and maybe close this one, if we're agreed that passing components is the better solution?)

@ChrisTalman
Copy link

I just raised a StackOverflow question relating to this topic.

Being able to pass components through other components seems to be a very important capability in being able to create abstract and dynamic components which are able to fully hook into the Svelte lifecycle by default. Currently, this seems difficult.

@Rich-Harris
Copy link
Member

Will close this in favour of #640, as it seems like that's the best solution to this problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants