How to pass props using slots from parent to child -vuejs - vue.js

I have a parent component and a child component.
The parent component's template uses a slot so that one or more child components can be contained inside the parent.
The child component contains a prop called 'signal'.
I would like to be able to change data called 'parentVal' in the parent component so that the children's signal prop is updated with the parent's value.
This seems like it should be something simple, but I cannot figure out how to do this using slots:
Here is a running example below:
const MyParent = Vue.component('my-parent', {
template: `<div>
<h3>Parent's Children:</h3>
<slot :signal="parentVal"></slot>
</div>`,
data: function() {
return {
parentVal: 'value of parent'
}
}
});
const MyChild = Vue.component('my-child', {
template: '<h3>Showing child {{signal}}</h3>',
props: ['signal']
});
new Vue({
el: '#app',
components: {
MyParent,
MyChild
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<my-parent>
<my-child></my-child>
<my-child></my-child>
</my-parent>
</div>

You need to use a scoped slot. You were almost there, I just added the template that creates the scope.
<my-parent>
<template slot-scope="{signal}">
<my-child :signal="signal"></my-child>
<my-child :signal="signal"></my-child>
</template>
</my-parent>
Here is your code updated.
const MyParent = Vue.component('my-parent', {
template: `<div>
<h3>Parent's Children:</h3>
<slot :signal="parentVal"></slot>
</div>`,
data: function() {
return {
parentVal: 'value of parent'
}
}
});
const MyChild = Vue.component('my-child', {
template: '<h3>Showing child {{signal}}</h3>',
props: ['signal']
});
new Vue({
el: '#app',
components: {
MyParent,
MyChild
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<my-parent>
<template slot-scope="{signal}">
<my-child :signal="signal"></my-child>
<my-child :signal="signal"></my-child>
</template>
</my-parent>
</div>
The release of Vue 2.6 introduces a unified v-slot directive which can be used for normal or scoped slots. In this case, since you're using the default, unnamed slot, the signal property can be accessed via v-slot="{ signal }":
<my-parent>
<template v-slot="{ signal }">
<my-child :signal="signal"></my-child>
<my-child :signal="signal"></my-child>
</template>
</my-parent>

I added this code inside of <v-data-table></v-data-table>
<template
v-for="slot in slots"
v-slot:[`item.${slot}`]="{ item }"
>
<slot
:name="slot"
:item="item"
/>
</template>
And I added a props called slots. When I call the component I send a slots like:
<my-custom-table-component :slots="['name']">
<template v-slot:name="{ item }">
{{ item.first_name + item.last_name}}
</template>
</my-custom-table-component>

You may try this technique.
In this example.
Let assume a parent component wants to share prop foo with value bar.
Parent component
<parent>
<template v-slot:default="slotProps">
// You can access props as object slotObjects {foo"bar"}
<p>{{slotProps.foo}}</p>
</template>
<parent>
Child
<template>
<div class="parent">
<slot :foo="bar" />
</div>
</template>
Got the idea from this video
I hope it helped you accomplish your tasks.

Related

How to use v-model using props in v-for in Vue 3

I want to use v-model using props in v-for. I used v-model with props before using computed variables, but don't know how to do in v-for.
This is my code:
<script setup>
const fieldValue = computed({
get() {
return props.modelValue;
},
set(value) {
emits('update:modelValue', value);
},
});
</script>
<template>
<Mentionable
v-for="(field, index) in props.data.placeholder"
:key="index"
:keys="['#']"
:items="props.data.items"
>
<textarea
v-model="fieldValue"
:disabled="!props.data.loaded"
:placeholder="field.placeholder"
:maxlength="props.maxLength"
:required="props.required"
/>
</Mentionable>
</template>
Note: Mentionable is the component from vue-mention library.
Use model-value and update:model-value event instend of v-model.
If the component does not provide model-value and update:model-value event, there must be prop and event you can do the same.
A example, AInput from Ant Design Vue provides value prop and change event.
<script setup name="Demo">
const {ref} from 'vue'
const arrayInputs = ref(['1', 'test', '3'])
function change(i, event) {
arrayInputs.value[i] = event.target.value
}
</script>
<template>
<div class="vue-component">
<h2>ant-design-vue</h2>
<template v-for="(item, index) in arrayInputs" :key="index">
<!-- the index is important -->
<AInput :value="item" #change="event => change(index, event)" />
</template>
<div>{{ arrayInputs }}</div>
</div>
</template>

Passing props to deactivated component in Vue

I've implemented the Tab feature using "keep-alive", like below, I want to pass "items2" data to the component when the selected currentTabComponent is 'Old', how do i make this work? is there any workaround?
<template>
<div>
<button #click="currentTabComponent = 'New'"> New </button>
<button #click="currentTabComponent = 'Old'"> Old </button>
</div>
<keep-alive>
<component :is="currentTabComponent" :items="currentTabComponent === 'New' ? items : items2"></component>
</keep-alive>
</template>
In the logic, i have,
<script>
export default {
data() {
return {
currentTabComponent: "New",
items:['one','two','three'],
items2:['five','six','seven']
}
}
}
</script>
Even if you use keep-alive props will be passed in the usual way, dynamic or not. So if there is a change in props it should reflect in the subcomponent. keep-alive specifically helps in preserving state changes when the component is not used, and not resetting the state when the component is shown again. But in both cases, props will work fine.
Check the below code:
<div id='component-data'>
<button
v-for="tab in tabs"
v-bind:key="tab"
v-on:click="currentTab = tab">
{{ tab }}
</button>
<keep-alive>
<component v-bind:is="currentTab"
:items="currentTab == 'Bags' ? bags : shirts"
class="tab"></component>
</keep-alive>
</div>
<script>
Vue.component('Bags', {
props: ['items'],
template: "<div>Showing {{ items.toString() }} items in bags.</div>"
});
Vue.component('Shirts', {
props: ['items'],
template: "<div>Showing {{ items.toString() }} items in shirts.</div>"
});
new Vue({
el: "#component-data",
data: {
tabs: ['Bags', 'Shirts'],
currentTab: 'Bags',
bags: ['Bag one', 'Bag two'],
shirts: ['Shirt one', 'Shirt two']
}
});
</script>
You should make sure that the sub-components 'New' and 'Old' have declared the items props in their component definition. Also I hope 'New' and 'Old' are the registered names of the components you are using for tabs.

Vue.JS - Avoid re-rendering of slots when parent re-renders

I'm struggling on Vue.JS with a component that has as children/slots some "complex" components with canvas data (e.g. Maps).
I want to avoid that when the parent component re-renders, their inner slots re-render. Because of how this components work (or any other scenario), every time it re-renders it needs to do all of it's "loading" steps. Even when saving their real-time state.
For example:
Component.vue
<template>
<div>
<span>{{value}}</span>
<slot></slot>
</div>
</template>
View
<Component v-model="value">
<Map :latitude="0" :longitude="0"/>
</Component>
<script>
this.value = "Hello";
setTimeout(()=>{
this.value="Hello world!";
},1000);
</script>
Is there any way to prevent from slots from re-rendering when their parent re-renders?
Thanks in advance.
Hello use props for a child component, and this child is not will rerender
App
<template>
<div id="app">
<HelloWorld msg="Hello Vue in CodeSandbox!" :somedata="key">
slot information key: {{ key }}
</HelloWorld>
<button #click="key++">key++</button>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld,
},
data() {
return {
key: 0,
};
},
};
</script>
Child
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h3>somedata from props: {{ somedata }}</h3>
<hr />
<slot></slot>
<hr />
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: {
type: String,
default: "",
},
somedata: {
type: Number,
default: 999,
},
},
created() {
console.log("renred");
},
};
</script>
How you can see I used console.log("renred"); in the child component, you can check the console, the information will be shown only one time.
https://codesandbox.io/s/naughty-platform-ib68g?file=/src/components/HelloWorld.vue

how to substitute named slot from parent to child to grandchild with Vuejs

I am faced with a situation to render a third party date picker and also get the value from the third party component. since it is a third party i can't define a prop on it. However, the third party component provides an ability to pass variable in v-model.
So the design of my components requires me to be able to pass named slot from parent to child to grandchild.
for example;
//============ enter-or-upload-task.js =============
Vue.config.productionTip = false;
const sourceoftruth = {orderdate:''};
Vue.component('upload-by-csv',{
template:
`<div><input type="file" /></div>
`
});
//here i want to use the date picker
Vue.component('enter-task-by-form',{
data:function(){
return {
sourceoftruth
};
},
methods:{
getOrderDate: function(){
console.log(sourceoftruth.orderdate);
}
},
template:
`<div>
<label>Order Date:</label>
<!--Hoping to get datepicker component displayed here -->
<slot name="picker"></slot>
<input type="submit" #click.prevent = "getOrderDate()" />
</div>
`
});
const EnterTaskOrUploadByCSV = {
template:
`<div>
<upload-by-csv></upload-by-csv>
<enter-task-by-form>
<!-- wish to pass this named slot to this component -->
<slot name="picker"></slot>
</enter-task-by-form>
</div>
`
}
new Vue({
el:"#app",
data:{
sourceoftruth
},
components:{
'datepicker':vuejsDatepicker,
'enter-form-or-csv':EnterTaskOrUploadByCSV
}
})
// ===========================================================
The index.html is
<script src="./js/lib/vue.js></script>
<script src="./js/lib/vuejs-datepicker.js"></script>
<div id="app">
<enter-form-or-csv>
<datepicker v-model="sourceoftruth.orderdate" slot="picker">
</datepicker>
</enter-form-or-csv>
</div>
<script src = "./js/components/enter-or-upload-task.js"></script>
I have tried passing the named slot to the appropriate position but couldn't get it working. Please I need help on how to solve this.
Glad it's working now. The changes I made that it to work
in EnterTaskOrUploadByCSV i added a template slot to hold the datepicker component going to be received from the parent. then the grandchild component would be expecting the template named slot.
const EnterTaskOrUploadByCSV = {
template:
`<div>
<upload-by-csv></upload-by-csv>
<enter-task-by-form>
<template slot="passpicker">
<slot name="picker"></slot>
</template>
</enter-task-by-form>
</div>
`
}
The grandchild component expecting the template named slot.
Vue.component('enter-task-by-form',{
data:function(){
return {
sourceoftruth
};
},
methods:{
getOrderDate: function(){
console.log(sourceoftruth.orderdate);
}
},
template:
`<div>
<label>Order Date:</label>
<!-- Datepicker will show now -->
<slot name="passpicker"></slot>
<input type="submit" #click.prevent = "getOrderDate()" />
</div>
`
});

vue.js 2 how to properly nest components

Can you please tell me how to properly add components to other components?
The example below does not work. The child component is not displayed inside the parent.
<div id="app">
<parent>
<child></child>
</parent>
</div>
<template id='child'>
<div>child component</div>
</template>
<template id='parent'>
<div>parent component</div>
</template>
<script>
var child = {
template: '#child',
data: function () {
return {}
}
};
var parent = {
template: '#parent',
data: function () {
return {}
}
};
new Vue({
el: '#app',
components: {
'parent': parent,
'child': child
}
})
</script>
sample: https://jsfiddle.net/05gc05sk/1/
how to properly nest components?
Your code does work.
Only add <slot> (Content Distribution with Slots) to your parent component.
<template id='parent'>
<div>
parent component
<slot></slot>
</div>
</template>