Vue: Make scopes available for all components in the hierarchy

Created on 9 Mar 2017  路  13Comments  路  Source: vuejs/vue

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?

feature request

Most helpful comment

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
  })
}

All 13 comments

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

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?

You have props, slots and render function to achieve anything 馃榿

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.

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
  })
}

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:

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

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

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.

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

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.

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

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.

@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.

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

franciscolourenco picture franciscolourenco  路  3Comments

bfis picture bfis  路  3Comments

fergaldoyle picture fergaldoyle  路  3Comments

paceband picture paceband  路  3Comments

gkiely picture gkiely  路  3Comments