Set v-model value within a slot in Vuejs - vue.js

I have two components
child-component.vue
<template>
<div class="container">
<slot>
</div>
</template>
parent-component.vue
<template>
<my-component>
<input type="text" v-model="myinput1">
<input type="text" v-model="myinput2">
<input type="text" v-model="myinput3">
</my-component>
</template>
<script>
export default {
data() {
return {
myinput1: '',
myinput2: '',
myinput3: '',
}
}
}
</script>
I need to set the values of each input field inside the slot directly from child-component (the number of input fields could change).
Is there a way to achieve it without triggering an event from child component?
Thanks

EDIT - modified the code to handle variable number of inputs
In the child component
<template>
<div class="container">
<slot :data="slotData" />
</div>
</template>
<script>
export default
{
data()
{
return {
slotData: ['1', '2', '3']
};
}
}
</script>
In the parent component
<template>
<my-component>
<template slot-scope="props">
<input v-for="item in props.data" type="text" v-model="item">
</template>
</my-component>
</template>

Related

Vue.js child component to populate the slots of a dynamic component inside parent component

How can I render the header slot to the table component from the child component? This code is not working:
Table component
<template>
<div>
<slot name="header"></slot>
</div>
</template>
Parent component
<template>
<div>
<component :is="currentComponent" > </component>
</div>
</template>
<script>
export default {
data() {
return {
currentComponent: 'Table'
};
},
};
</script>
Child component
<template>
<div>
<parent-component>
<template slot="header">
<h1>test</h1>
</template>
</parent-component>
</div>
</template>
Tried the code above but it dosent work
Expecting to render title from child component
Solution:
Table component
<template>
<div>
<slot name="header"></slot>
</div>
</template>
Parent component
**<template>
<div>
<component :is="currentComponent" >
<template v-for="(_, name) in $slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}" />
</template>
</component>
</div>
</template>**
<script>
export default {
data() {
return {
currentComponent: 'Table'
};
},
};
</script>
Child component
<template>
<div>
<parent-component>
<template slot="header">
<h1>test</h1>
</template>
</parent-component>
</div>
</template>

Vue.JS: Communication with component

I have two component Header and AddUser component. Inside Header component I have a button that has function to show modal. And the modal is inside AddUser component like below.
Header.vue
<template>
<header>
<h2>{{title}}</h2>
<p>{{description}}</p>
<div class="text-center btn-class">
<button #click="showModal = true">Add Vehicle</button>
</div>
</header>
</template>
<script>
export default{
name: 'Header',
props: {
title: {
type: String,
default: 'Title!!',
},
description: {
type: String,
default: 'Description!!',
}
}
}
</script>
AddUser.vue
<template>
<div>
<transition name="fade" appear>
<div class="modal-overlay" v-if="showModal" #click="showModal = false"></div>
</transition>
<transition name="slide" appear>
<div class="modal" v-if="showModal">
<h3>Enter your vehicle detail</h3>
<div class="body">
<form #submit="onSubmit">
<div class="form-group">
<input type="text" v-model="name" name="name" class="form-control" placeholder="Enter your name">
</div>
<br><br>
<div class="form-btn form-group text-center">
<Button type="submit" text="Add" color="#2BA0A3" />
</div>
</form>
</div>
</div>
</transition>
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'AddUser',
data(){
return {
showModal: false,
name: ''
}
},
components: {
Button
},
methods: {
onSubmit(e){
e.preventDefault()
if(!this.name){
alert('Please enter name.')
}
},
}
}
</script>
And this is my App.vue
<template>
<div class="container">
<Header />
<AddUser />
</div>
</template>
<script>
import Header from './components/Header'
import AddUser from './components/AddUser'
export default {
name: 'App',
components: {
Header,
AddUser,
}
}
</script>
The code works perfectly if I put button inside AddUser.vue but I want to keep the button on Header.vue and want it work also. How can I make it both component to communicate?
Move your showModal variable to your App.vue and pass it to your AddUser component as a prop. Inside your Header and AddUser components you will need to update the showModal value by emitting a show-modal-event with the value true or false depending on if you want to show or hide the modal. Listen for the event in App.vue and update it's local data showModal value with the $events value.
Here is an example. ** FYI this code isn't tested so there might be typos.
Header.vue
<template>
<header>
<h2>{{title}}</h2>
<p>{{description}}</p>
<div class="text-center btn-class">
<button #click="$emit('show-modal-event', true)">Add Vehicle</button>
</div>
</header>
</template>
<script>
export default{
name: 'Header',
props: {
title: {
type: String,
default: 'Title!!',
},
description: {
type: String,
default: 'Description!!',
}
}
}
</script>
AddUser.vue
<template>
<div>
<transition name="fade" appear>
<div class="modal-overlay" v-if="showModal" #click="$emit('show-modal-event', false)"></div>
</transition>
<transition name="slide" appear>
<div class="modal" v-if="showModal">
<h3>Enter your vehicle detail</h3>
<div class="body">
<form #submit="onSubmit">
<div class="form-group">
<input type="text" v-model="name" name="name" class="form-control" placeholder="Enter your name">
</div>
<br><br>
<div class="form-btn form-group text-center">
<Button type="submit" text="Add" color="#2BA0A3" />
</div>
</form>
</div>
</div>
</transition>
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'AddUser',
data(){
return {
name: ''
}
},
props: {
showModal: {
type: Boolean,
default: false
}
},
components: {
Button
},
methods: {
onSubmit(e){
e.preventDefault()
if(!this.name){
alert('Please enter name.')
}
},
}
}
</script>
App.vue
<template>
<div class="container">
<Header #show-modal-event="showModal=$event" />
<AddUser #show-modal-event="showModal=$event" :showModal="showModal" />
</div>
</template>
<script>
import Header from './components/Header'
import AddUser from './components/AddUser'
export default {
name: 'App',
components: {
Header,
AddUser,
},
data(){
return {
showModal: false,
}
},
}
</script>

How to pass data to the $slots in child component?

I have two components
Navigation
Alert
Alert is Navigation's child
Navigation code
<template>
<div class="col-lg-5">
<base-alert :icon="`fa fa-facebook`"></base-alert>
</div>
</template>
<script>
export default {
data() {
return {
error: 'This is error'
}
}
}
</script>
Base alert code
<slot>
<span v-if="icon" class="alert-inner--icon">
<i :class="icon"></i>
</span>
<span v-if="$slots.text" class="alert-inner--text">
<slot name="text"></slot>
</span>
</slot>
Currently this is what I got
My problem right now how do i pass the error data to the base-alert $slots.text?
Regards
You need to add <template slot="text">{{ error }}</template> as below. Where text is the name of slot you have mentioned in Base Alert
Navigation Code
<template>
<div class="col-lg-5">
<base-alert :icon="`fa fa-facebook`">
<template slot="text">{{ error }}</template>
</base-alert>
</div>
</template>
<script>
import baseAlert from "./base-alert";
export default {
components: { baseAlert },
data() {
return {
error: "This is error"
}
}
}
</script>
Base Alert
<template>
<div>
<slot>
<span v-if="icon" class="alert-inner--icon">
<i :class="icon"></i>
</span>
<span v-if="$slots.text" class="alert-inner--text">
<slot name="text"></slot>
</span>
</slot>
</div>
</template>
<script>
export default {
name: "base-alert",
props: ["icon"]
};
</script>
<style scoped></style>
Pass your error message down as a prop to the child.
Navigation code
<template>
<div class="col-lg-5">
<base-alert :error="error" :icon="`fa fa-facebook`"></base-alert>
</div>
</template>
<script>
export default {
data() {
return {
error: 'This is error'
}
}
}
</script>
Base alert code
<slot>
<span v-if="icon" class="alert-inner--icon">
<i :class="icon"></i>
</span>
<span v-if="error" class="alert-inner--text">
<div>{{ error }}</div>
</span>
</slot>

How to make this Vue.js component to work?

I have this component with default data that I want to reuse on other pages with other data:
CustomCard.vue
<template>
<div>
<v-layout >
<v-flex md4 class="white">
<div>
<slot class="top-img">
<img src="../assets/default.jpg" alt="">
</slot>
<slot class="description">
<p>default description</p>
</slot>
</div>
</v-flex>
</v-layout>
</div>
</template>
<script>
export default {
}
</script>
Page1.vue
<template>
<div>
<custom-card>
</custom-card>
</div>
</template>
<script>
export default {
}
</script>
Question:
What should I do in order to use CustomCard.vue component on Page1.vue page with another data:
src="../assets/image1.jpg"
"changed description"
You should import the component CustomCard in the component where you want to use it, and then add it in components option from your vue object.
After this you are ready to use it in your template.
<template>
<div id="app">
<custom-card/>
</div>
</template>
<script>
import CustomCard from './components/CustomCard' . // <-- This
export default {
components: {
CustomCard // <--This
}
}
If you want to use different data... you can pass them by props like this:
<custom-card :data="newData"/>

vue-multiselect does not load CSS

I am using vue-multiselect component (b15) with vue-cli (webpack template) but the component's CSS is not loaded and the component renders wrong. Any idea?
My code:
<template>
<div>
<div class="select2-container select2-container-multi full-width">
<multiselect
class="form-control form-control-select textarea"
:class="{ 'has-error': showError }"
:options="localOptions"
:label="labelKey"
track-by="id"
:multiple="multiple"
:selected="value"
:searchable="true"
:placeholder="placeholder"
:loading="loading"
:custom-label="formatLabel"
:disabled="disabled"
:readonly="readonly"
#input="updateSelected"
#close="blur">
</multiselect>
</div>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
mixins: [inputMixin],
components: {
Multiselect
}
}
</script>
Multiselect is rendered and everything just no style is applied.
You need to add css seperately at the end, so you file looks like that:
<template>
<div>
<div class="select2-container select2-container-multi full-width">
<multiselect
class="form-control form-control-select textarea"
:class="{ 'has-error': showError }"
#input="updateSelected"
#close="blur">
</multiselect>
</div>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
mixins: [inputMixin],
components: {
Multiselect
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>