Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VueJS - Pass slot to child of child component

Tags:

I have a list and a list_item component that I reuse a lot inside my application. On a simplified form:

contact_list.vue

<template lang="pug">     .table         .table-header.table-row         .table-col Contact         .table-col Info        .table-body           contact-list-item(v-for='contact in contacts',                             :contact='contact',                             @click='doSomething()')  </template> 

contact_list_item.vue

<template lang="pug"> .table-row(@click='emitClickEvent')   .table-col {{ contact.name }}   .table-col {{ contact.info }} </template> 

When I use contact_list inside a specific component, I want to be able to send a slot that will add some new columns to the contact_list_item component. This slot will use data of the specific contact that is being rendered inside that contact_list_item component to generate the new columns.

How could I achieve that? Is using slot the best approach?

Thanks in advance.

like image 854
felipeecst Avatar asked Jul 03 '17 14:07

felipeecst


2 Answers

Slots are the best approach and you will need to use a scoped slot for the contact-list-item component. I'm not really familiar with pug, so I will use HTML for the example.

In contact-list you would add a slot. Notice in this case that the contact is being passed as a property. This is so we can take advantage of scoped slots.

<div class="table">   <div class="table-header table-row">       <div class="table-col">Contact</div>     <div class="table-col">Info</div>   </div>   <div class="table-body">     <contact-list-item v-for='contact in contacts'                        :contact="contact"                        @click="doSomething"                        :key="contact.id">       <slot :contact="contact"></slot>     </contact-list-item>   </div> </div> 

Then add a slot to the contact-list-item.

<div class="table-row" @click="emitClickEvent">   <div class="table-col">{{contact.name}}</div>   <div class="table-col">{{contact.info}}</div>   <slot></slot> </div> 

Finally, in your Vue template, use the scoped template.

<div id="app">   <contact-list :contacts="contacts">     <template scope="{contact}">       <div class="table-col">{{contact.id}}</div>     </template>   </contact-list> </div> 

Here is a working example. I have no idea what your styles are but notice the id column is now displayed in the contact-list-item.

like image 61
Bert Avatar answered Sep 21 '22 09:09

Bert


You can use template for registering slot to the child of child component.

There is also a case when you want to have many named slots.

child.vue

<template>   <div>     <h2>I'm a father now</h2>     <grandchild :babies="babies">       <template v-for="(baby, id) in babies" :slot="baby.name">         <slot :name="baby.name"/>       </template>     </grandchild>   </div> </template> 

grandchild.vue

<template>   <div>     <p v-for="(baby, id) in babies" :key="id">       <span v-if="baby.isCry">Owe...owe...</span>       <slot :name="baby.name">     </p>   </div> </template> 

parent.vue

<template>   <div>     <h2>Come to grandpa</h2>     <child :babies="myGrandChilds">       <button slot="myGrandChilds[2].name">baby cry</button>     </child>   </div> </template> 
like image 42
DrSensor Avatar answered Sep 21 '22 09:09

DrSensor