Pablo Gablo
Pablo Gablo

Reputation: 55

vue: passing props down to all descendants

I have a parent component with the following line

<router-view :product-id="productId" :data-source="attributes"></router-view>

depending on the context it renders one of the two components defined in the router config

path: 'parent',
component: Parent,
children:
[
    {
        path: 'edit',
        component: Edit,
        children:
        [
            {
                path: 'attribute/:id',
                component: Attribute,
            }
        ]
    },
    {
        path: 'grid',
        component: Grid,
    }
]

The thing is that the product-id and data-source props are available only in the Edit and Grid components. I'd like to have them available in the Attribute component as well as the Edit component is just a background with some static text (common for many components).

As a workaround I've created a propertyBag prop in the Edit component that passes an object down. That's the way I use it in the parent component

 <router-view :property-bag="{ productId:productId, dataSource:dataSource, ...

and the Edit component

<router-view :property-bag="propertyBag"></router-view>

Is there a simpler way to achieve it ?

Upvotes: 3

Views: 11712

Answers (7)

Eric G
Eric G

Reputation: 2617

You must pass all data via props to children components. You don't have to pass it as an object but Vue.js does require all data to be passed to children. From their documentation:

Every component instance has its own isolated scope. This means you cannot (and should not) directly reference parent data in a child component’s template. Data can be passed down to child components using props.

So you are doing it in the correct manner. You don't have to create an object, you are able to pass as many props as you would like but you do have to pass the from each parent to each child even if the parent is a child of the original "parent".

Upvotes: 0

cloudpre
cloudpre

Reputation: 1001

Vue $attrs is the new way to propagate props

From the Docs:

vm.$attrs

Contains parent-scope attribute bindings (except for class and style) that are not recognized (and extracted) as props. When a component doesn’t have any declared props, this essentially contains all parent-scope bindings (except for class and style), and can be passed down to an inner component via v-bind="$attrs" - useful when creating higher-order components.

For more information, see Vue.js API Reference - $attrs

Upvotes: 9

Daniel
Daniel

Reputation: 35684

You have to declare the props and bind them to pass them to the child. Have a look at https://v2.vuejs.org/v2/api/#v-bind for available options

specifically, this may be of interest

<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- but you can also... -->
<div v-bind="allProps"></div>

This means you can pass down the object, and have the child parse the appropriate props. This means that the child has to have the props defined in order to catch them. So what you may be able to do is, in the case of the parent, have :propBag="propBag" and inside edit, pass down v-bind="propBag", and that will use the correct props at the child level

Upvotes: 2

Lazaros Kosmidis
Lazaros Kosmidis

Reputation: 749

for vue > 2.0

v-bind="$attrs" it's sufficient, or you can declare them at data(), with [this.$attrs]

Upvotes: 2

Aerodynamic
Aerodynamic

Reputation: 819

How to pass multiple Props Downstream to Components

Use case: Props that you only need on the n-th child components, you can simply forward downstream without having to define the same props all over again in each component.

Correction: v-bind="$attrs" works just fine. Just make sure the parent also uses v-bind="$attrs" and not v-bind="$attr" ('s' was missing) which was the error that made me think v-bind="{ ...$attrs }" was needed.

However, I think you should still be able to use v-bind="{ ...$attrs }" to access all previous attributes, even if parents didn't explicitly propagated them.

How to: Based on Alexander Kim's comment, it must be v-bind="{ ...$attrs }".

... is needed to pass the attributes of the previous component (parent) as $attrs only passes the attributes of the current component.

v-bind="{ ...$attrs }"

Upvotes: 0

Alex83690
Alex83690

Reputation: 817

Solution possible from Vue 2.2.0

provide / inject

This pair of options are used together to allow an ancestor component to serve as a dependency injector for all its descendants, regardless of how deep the component hierarchy is, as long as they are in the same parent chain.

https://fr.vuejs.org/v2/api/index.html#provide-inject

Upvotes: 0

PrestonDocks
PrestonDocks

Reputation: 5408

Have you looked at vuex. It's really quite easy to use and allows you to store data for your entire app in a single data store. This means you don't have to keep passing data through props, you can just access variables set in the store.

Here is a link to vuex docs (What is Vuex) https://vuex.vuejs.org

Upvotes: 3

Related Questions