Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vue wrap another component, passing props and events

Tags:

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?

like image 619
user3599803 Avatar asked Jun 11 '18 15:06

user3599803


People also ask

What is a wrapper in Vue?

A Wrapper is an object that contains a mounted component or vnode and methods to test the component or vnode.

How do you put a component inside another component in Vue?

You need to create your portfolio component first e.g. in src/components/Projects/Portfolio. vue and then import it inside the script tag within your Landing.


1 Answers

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>
like image 186
BCDeWitt Avatar answered Oct 02 '22 10:10

BCDeWitt