8000 Make scopes available for all components in the hierarchy · Issue #5151 · vuejs/vue · GitHub
[go: up one dir, main page]

Skip to content

Make scopes available for all components in the hierarchy #5151

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

Closed
johannes-z opened this issue Mar 9, 2017 · 13 comments
Closed

Make scopes available for all components in the hierarchy #5151

johannes-z opened this issue Mar 9, 2017 · 13 comments

Comments

@johannes-z
Copy link

Vue.js version

2.2.2

Reproduction Link

https://jsfiddle.net/6ofnoyg6/1/

What is expected?

I'd think that the templates defined in the "main" component would get passed down to all the components, including the full hierarchy. As you can see in the example, only the container has the $scopedSlots, while the #app component does not. Hence you can't overwrite slots over multiple levels, which would force you to either

  • define the templates inside container component -> lose the ability to customize the components output / you need multiple prerendered files for each customization
  • or not using the child component and instead define everything in the container component -> more unreadable, unmaintainable code.

I've also asked on gitter and stackoverflow, but didn't get any answers (so far). I think this isn't possible by design, but is this intended?

@posva
Copy link
Member
posva commented Mar 9, 2017

Yes, this is intended: making a slot to go through a parent component to get to its inner child is something you cannot know when using the parent component (aka implicit). It's harder to reason about, also imagine the mess if both, parent, and children have slots. Where should the content go?
For your use case, it's better to pass down the scoped slot yourself

@johannes-z
Copy link
Author
johannes-z commented Mar 9, 2017

Where should the content go?

I've read on other issues, that the slots don't provide inheritance (which is fine, I guess). So I was thinking, regarding this question, that the content should always go to "the closest component" where it is defined (assuming the slots were distributed to all the inner children etc.)

For your use case, it's better to pass down the scoped slot yourself

This is what I tried, but I was trying to set the $scopedSlots property on the inner child, based on the parents $scopedSlots - which of course doesn't work, because it's readonly. Maybe I've overlooked it somehow, but I don't think that there is an API to do that?

@posva
Copy link
Member
posva commented Mar 9, 2017

You have props, slots and render function to achieve anything 😁

@johannes-z
Copy link
Author
johannes-z commented Mar 9, 2017

Regarding my jsfiddle example: So you would pass down the $scopedSlots as prop to the child component, and use them in its render function?

edit: Just a quick implementation: https://jsfiddle.net/6ofnoyg6/4/ I don't know about you, but this seems overly complicated for something so simple. Other than the reason that it "gets harder to reason" about, I really would expect the slots to be passed down the hierarchy.

@yyx990803
Copy link
Member

When you use <child></child> there's nothing inside, so there would be no slots nor scoped slots passed down.

Passing down scoped slots is as simple as:

render (h) {
  return h('child', {
    scopedSlots: this.$scopedSlots
  })
}

@kowd
Copy link
kowd commented Mar 14, 2017

How would this work with a template rather than a render function?

I have a tree component where you assign the scoped slots on the container and then the container items do:

  created () {
    this.$scopedSlots = this.$parent.$scopedSlots
  }

This stopped working once I updated from v2.1 to v2.2

@johannes-z
Copy link
Author

I think you could use a v-for over $scopedSlots to pass them to the compnent in your template. I did not try that though yet, although I'll have the same problem after reworking my code (with render functions it works fine).
Alternatively, I think you could use JSX in your vue template, to use "templates" and still have the power of render functions. That's what I'm doing right now for my templates, and it works perfectly fine.

@CreativSpeed
Copy link

use the newly added feature provide / inject

parent component:

provide: {
  foo: 'bar'
}

add it to the child component
inject: ['foo']

use it with
this.foo

@johannes-z
Copy link
Author

provide and inject don't seem to work for $scopedSlots, since you can't assign this.$scopedSlots inside the provide function (because: "Note: the provide and inject bindings are NOT reactive")

Also, render functions are not necessarily a good solution. I came across a problem, where I need to distribute slots, across multiple levels, where render functions are impracticable because of the large templates that come wit the components.

@yyx990803 Can we use provide/inject or something similar that goes well with components with templates to distribute slots to child components?

F.e. this could be useful, if you have date-objects that should be rendered in multiple components. Instead of changing the source, a slot could be used in those components to render the date-object as a localeDateString. Having a root component that provides this slot would simplify a lot of things.

@CreativSpeed
Copy link

i recommend you use vuex in case you are building a large App, and store this.$scopedSlots globally to get them using vuex ...mapGetters

@johannes-z
Copy link
Author

To show what I'm talking about, I created a repo with a very simple project that shows the problem with slot distribution over multiple levels. Since this project is so simple, using vuex is counterproductive in my opinion.

@johannes-z
Copy link
Author

@posva, @yyx990803 bump. I know you closed this, but regardless, this is still an issue. There should be an easier mechanism to distribute slots over an arbitrary component-hierarchy, so that component that render the templates can utilize them. If any of the components within the hierarchy have a more complex template, using a render function becomes very tedious, even so if you use JSX. In my use case, the render function which I had to write became almost unreadable, because of nesting VNodes so often.

@posva
Copy link
Member
posva commented Apr 12, 2017

Please, don't spam... You should ask the question on the forums with concrete samples of your code (I know there's a repo). For instance, you should show the JSX that you think is unreadable, but please, do so on the forums

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

No branches or pull requests

5 participants
0