vue wrap another component, passing props and events
Asked Answered
I

1

25

How can I write my component to wrap another vue component, while my wrapper component get some extra props? My wrapper template component should be:

<wrapper-component>
   <v-table></v-table> <!-- pass to v-table all the props beside prop1 and prop2 -->
</wrapper-component>

and the wrapper props:

props: {
  prop1: String,
  prop2: String
}

Here I want to wrap a table component, and pass to the table component all the props and events that were passed to the wrapper, beside two extra props prop1 and prop2. What is the correct way of doing this in vue? And is there a solution for events too?

Intercontinental answered 11/6, 2018 at 15:12 Comment(1)
This is specifically what $listeners and $props are for.Bank
B
51

Place the component you wish to wrap into the template of the wrapper component, add v-bind="$attrs" v-on="$listeners" to that component tag, then add the inner component (and, optionally, inheritAttrs: false) to the wrapper component's config object.

Vue's documentation doesn't seem to cover this in a guide or anything, but docs for $attrs, $listeners, and inheritAttrs can be found in Vue's API documentation. Also, a term that may help you when searching for this topic in the future is "Higher-Order Component" (HOC) - which is basically the same as your use of "wrapper component". (This term is how I originally found $attrs)

For example...

<!-- WrapperComponent.vue -->
<template>
    <div class="wrapper-component">
        <v-table v-bind="$attrs" v-on="$listeners"></v-table>
    </div>
</template>

<script>
    import Table from './BaseTable'

    export default {
        components: { 'v-table': Table },
        inheritAttrs: false // optional
    }
</script>

Edit: Alternatively, you may want to use dynamic components via the is attribute so you can pass in the component to be wrapped as a prop (closer to the higher-order component idea) instead of it always being the same inner component. For example:

<!-- WrapperComponent.vue -->
<template>
    <div class="wrapper-component">
        <component :is="wraps" v-bind="$attrs" v-on="$listeners"></component>
    </div>
</template>

<script>
    export default {
        inheritAttrs: false, // optional
        props: ['wraps']
    }
</script>

Edit 2: The part of OP's original question that I missed was passing all props EXCEPT one or two. This is handled by explicitly defining the prop on the wrapper. To quote the documentation for $attrs:

Contains parent-scope attribute bindings (except for class and style) that are not recognized (and extracted) as props

For example, example1 is recognized and extracted as a prop in the snippet below, so it doesn't get included as part of the $attrs being passed down.

Vue.component('wrapper-component', { 
  template: `
    <div class="wrapper-component">
        <component :is="wraps" v-bind="$attrs" v-on="$listeners"></component>
    </div>
  `,
  // NOTE: "example1" is explicitly defined on wrapper, not passed down to nested component via $attrs
  props: ['wraps', 'example1']
})

Vue.component('posts', {
  template: `
    <div>
      <div>Posts component</div>
      <div v-text="example1"></div>
      <div v-text="example2"></div>
      <div v-text="example3"></div>
    </div>
  `,
  props: ['example1', 'example2', 'example3'],
})

new Vue({
  el: '#app',
  template: `
    <wrapper-component wraps="posts"
      example1="example1"
      example2="example2"
      example3="example3"
    ></wrapper-component>
  `,
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
Borate answered 11/6, 2018 at 15:59 Comment(2)
Thanks for the answer , however OP asks how to exclude certain props. For example say I wrap a date-picker which accepts a v-model and timeZoneProp. My picker-wrapper has two props value(v-model) and timeZoneProp . Now I want timeZoneProp to be passed fown to the date-picker but I don't want the v-model to be passed as is , because inside the wrapper I do some data transform on the v-model and then inject down to the picker. How to solve such cases ie exclude certain 'props' but pass the rest down using $atts .Thanks in advancePubilis
@SainathS.R Looking back at this answer again, you're absolutely right. I'll update it, thanks!Borate

© 2022 - 2024 — McMap. All rights reserved.