VueJs - Using Slot name to call a component in another component - vue.js

I have a component 'ProgressCircular.vue'. I need to call this component in another component and my senior told me to use slot name.
Please help me out. Adding my progress circular component:
<template>
<div>
<v-overlay :value="true">
<v-row justify="center" align="center">
<div class="text-center ma-12">
<v-progress-circular
:rotate="rotate"
:size="size"
:value="value"
:width="width"
color="red"
indeterminate ></v-progress-circular>
</div>
</v-row>
</v-overlay>
</div>
</template>
<style scoped>
</style>
<script>
export default {
data: () => ({
indeterminate: true,
rotate: 0,
size: 50,
value: 0,
width: 1
}),
}
</script>
Vuetify link: https://v15.vuetifyjs.com/en/components/progress
Component where i need to integrate progresscircular is given below: DocumentComponent
<template>
<div class="components" :key="documentComponentkey">
<!--Document Version History Component-->
<DocumentHistoryComponents></DocumentHistoryComponents>
<!--Generic Header Component-->
<HeaderComponents></HeaderComponents>
<div class="components-sub-container">
<!--Generic Form Component-->
<BodyComponents></BodyComponents>
</div>
<!--Generic Footer Component-->
<FooterComponents></FooterComponents>
</div>
</template>
I need to call circular progress component in DocumentComponent using slot property in Circular progress component
Tried:
I have modified code as below:
<template #circularProgress>
<div>
<v-flex xs10 class="mx-auto progressbar">
<v-progress-circular :rotate="rotate || 360"
:size="size || 100"
:width="width || 7"
color="#557fb5"
:value="value || 0"
indeterminate v-html="value || 0">
</v-progress-circular>
</v-flex>
</div>
and my child component as:
<slot :value = 'uploadPercentage' :rotate="360" :size="100">{{uploadPercentage}}</slot>
I am getting uploadPercentage not the circular progress bar

Related

how to create button group component in vue

I am trying to create button-group component in vue using typescript:
<template>
<slot>
<CButton
v-for="(vnode, index) in $slots.default || []"
:key="index"
:class="[
{ 'first-index': index === 0 },
{ 'last-index': index === ($slots.default ? $slots.default.length : 0) - 1 },
]"
>
{{ index }}
{{ vnode }}
</CButton>
</slot>
</div>
</template>
Here index comes null but I am expecting it turns as much as button I added.
Here is the parent:
<ButtonGroup>
<CustomButton>1</CustomButton>
<CustomButton>2</CustomButton>
<CustomButton>3</CustomButton>
</ButtonGroup>
Here is how you need to use slots in Vue:
<!-- ButtonGroup -->
<template>
<div class="button-group">
<slot></slot> <!-- Define the default slot -->
</div>
</template>
<template>
<ButtonGroup>
<!-- Fill in the slot with whatever you want -->
<CustomButton class="my-class">Test</CustomButton>
<button class="regular-button">Normal</button>
<CustomButton />
</div>
</template>
Example playground

V-select issue in Vuetify 3

I'm using Vuetify 3.0.0-beta.0 ~ for my project (because it is the only version that supports vue3), and having a bit weird issue
I want to implement the same thing as described there https://codepen.io/reijnemans/pen/vYNadMo?editors=1010 with v-select involved, so I was needed to use Vuetify
copied snippet
<v-select
:items="items"
label="Standard"
>
<template v-slot:selection="{ item, index }">
<img :src="item.image">{{ item.name }}</template>
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}</template>
</v-select>
My Component:
<template>
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
:items="items"
label="Standard">
<template v-slot:selection="{ item }">
<img :src="item.image">{{ item.name }}
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}
</template>
</v-select>
</v-col>
</v-col>
</div>
</template>
<script>
import { mapState } from "vuex";
/* eslint-disable */
export default {
name: "testComponent",
data() {
return {
// hardware Configuration Validation Rules
items: [
{ name: 'Foo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Bar', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Hoo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Coo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'}],
}
}}
When I'm trying to run the above component I always get this weird error Failed setting prop "type" on <select>: value text is invalid. TypeError: Cannot set property type of #<HTMLSelectElement> which has only a getter,
Did anyone faced similar issue before?
In Vuetify 3, you need some workarounds to style the items in v-select, because the item slot resets the entire styling.
You should use the menu-props, with it you can pass props through to the v-menu component. It accepts an object with anything from /api/v-menu. This allows you to close the field on click.
In the item slot, you should use a v-list-item with an #click property to set the model.
I made an example here with a selection of symbols:
<script setup>
const symbols = [
'ab-testing',
'abacus',
'account',
'account-alert',
]
const form = { symbol: '', }
</script>
<template>
<v-select
v-model="form.symbol"
:items="symbols"
label="Symbol"
:prepend-inner-icon="'mdi-'+form.symbol"
:menu-props="{
closeOnClick: true,
closeOnContentClick: true,
}"
>
<template v-slot:selection="{ item, index }">
{{ item.value }}
</template>
<template v-slot:item="{ item, index }">
<v-list-item
:title="item.title"
:prepend-icon="'mdi-'+item.title"
#click="form.symbol = item.title"
>
</v-list-item>
</template>
</v-select>
</template>
I hope it helps you.
I couldn't find correct solution but I just wanted to share what I did about scoped slot. I think we should use item.raw to access name and image. And the next problem is how to make it clickable to trigger select event that I didn't know yet :(
const { createApp } = Vue
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const app = createApp({
data() {
return {
value: null,
items: [
{
name: 'Foo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Bar',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Hoo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Coo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
}
]
}
}
});
app.use(vuetify).mount('#app');
<link href="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.js"></script>
<div id="app">
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
v-model="value"
:items="items"
item-title="name"
item-value="name"
label="Standard">
<template v-slot:item="{item}">
<v-list-item
:prepend-avatar="item.raw.image"
:title="item.raw.name"
/>
</template>
</v-select>
</v-col>
</v-col>
</div>
</div>

How to access slot props from the component used inside the slot?

so everything i can find about scoped slots and passing props dont work for my specific situation:
i have following component order:
Home/List/ListItem
now i desided to replace the ListItem with a slot and because i use the List in a other Component too, but in there i need the ListOptionsItem.
in my home component i did this:
<list
class="mapkeyList"
:content="displayList"
:filterbar="true"
#handleSelection="addSelection"
#delete="deleteElement"
#editItem="editItem"
header="Mapkeys"
:key="mapkeyListKey"
>
<list-item>
</list-item>
</list>
in my List component i have this:
<template>
<div>
<h2 v-if="header">{{header}}</h2>
<div class="listContainer" v-if="showedContent.length > 0">
<div v-for=" (item, index) in showedContent" :key="index">
<slot
:item="item"
:index="index"
:dragable="dragableItems"
#auswahl="auswahlHandle"
#deleteElement="deleteElement"
#editItem="editItem"
:dontShowButtons="dontShowButtons"
#dragStart="handleOverDragStart"
:dragItem="dragItem"
#position="$emit('emitPosition',item)"
:deaktivierbar="deaktivierbar"
>
</slot >
</div>
finaly the listItem and the listOptionsItem need to access this props in the slot:
listItem:
<template>
<div class= "flexSpaceBetween" #click="$emit('auswahl',item)">
<div class="textFett">
{{item[0]}}
</div>
<div>
{{item[1]}}
</div>
</div>
i dont want to write all the neccessarry code in the home component because the listOptionsItem does need more informations and more space to write code.
my goal was it to define in the Home component that i want the list to use the listItem component and in the Options component the list should use the listItemOptions component. in the future there could be added new listItem versions.
Any component used inside scoped slot has no implicit access to the slot props. To make them available inside the component, you must pass it down to that component as props explicitly...
<list
class="mapkeyList"
:content="displayList"
:key="mapkeyListKey">
<template v-slot:default="{ item }">
<list-item :item="item">
</list-item>
</template>
</list>
If you have a lot of props/events you want to pass along, the ability of both v-bind and v-on to take an object as an argument is very useful because you can pass all the data and event handlers at the same time:
// List component
<template>
<div>
<h2 v-if="header">{{header}}</h2>
<div class="listContainer" v-if="showedContent.length > 0">
<div v-for=" (item, index) in showedContent" :key="index">
<slot :props="slotProps" :on="slotEventsHandlers"
</slot >
</div>
</div>
</div>
</template>
<script>
export default {
computed: {
slotProps() {
return {
item: this.item,
dragable: this.dragableItems
}
},
slotEventsHandlers() {
return {
deleteElement: this.deleteElement,
dragStart: this.handleOverDragStart
}
}
}
}
</script>
And use it in parent:
<list
class="mapkeyList"
:content="displayList"
:key="mapkeyListKey">
<template v-slot:default="{ props, on }">
<list-item v-bind="props" v-on="on">
</list-item>
</template>
</list>

Condition on template with v-if using v-slot prop

I'm trying to make a condition to enable a named slot like this:
<template v-slot:item="{ item }" v-if="item.loading">
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</template>
My use case is a Vuetify datatable: each item has a "loading" property, and I'd like to activate "item" slot only if the row is loading ("item" slot is Slot to replace the default rendering of a row)
The error is that item is undefined in the v-if, which seems logic : item is only defined for template children tag.
Is there a way to solve this problem?
You can filter the items that you pass to the datatable with a computed property.
Can you just not swap element based on loading ?
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: '#app',
data: {
items: [{data : "", loading: true}, {data : "Some data", loading: false}]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="item in items">
<div>
<div v-if="item.loading">
Loading...
</div>
<div v-else>
{{item.data}}
</div>
</div>
</div>
</div>
I had a similar problem, and I solved it in Vuetify 2 by importing VDataTable/Row as 'v-data-table-row', and using it to render 'regular' table rows, and for custom rows I used my own template.
JavaScript
import Row from 'vuetify/lib/components/VDataTable/Row.js';
export default {
components: { 'v-data-table-row': Row },
data() {
return {
currentItemName: 'Ice cream sandwich'
}
}
// headers, items, etc...
}
HTML
<template v-slot:item="{ item }">
<tr v-if="item.name == currentItemName" class="blue-grey lighten-4">
<td>Custom prefix - {{ item.name }}</td>
<td colspan="2">{{ item.calories }} - Custom suffix</td>
</tr>
<v-data-table-row v-else :headers="headers" :item="item">
<template
v-for="(index, name) in $scopedSlots"
v-slot:[name.substr(5)]="data"
>
<slot
v-if="name.substr(0, 5) === 'item.'"
:name="name"
v-bind="data"
></slot>
</template>
</v-data-table-row> </template
You can check out working example here.
You can just put the v-if on the child element
<template #item="{ item }">
<v-progress-circular
v-if="item.loading"
color="primary"
indeterminate
></v-progress-circular>
</template>

how we can go to child components in next button and back to parent components prev button in vuejs

I have 2 components a parent and a child. I want to show child component on parent's next button and parents component on child's previous button.
How can i do this?
Now I can call child component in next button but if i click the child component's prev button then parent component is not coming. How can i call parent component?
This is my parent component
<template>
<v-form>
<v-flex>
<div v-if="response.inputType == 'radio'" v-model="response.next" class="radio radio-success"
v-bind:id="response.id" >
<input type="radio" v-bind:id="'option'+ response.id" v-bind:name="index"
v-bind:next="response.next"
v-bind:rules="[v => !!v || 'You must agree to continue!']" v-bind:value="response.option" v-model="question.userResponses"
v-on:click="updateResponses" v-bind:checked="question.userResponses">
<label v-bind:for="'option'+ response.id" >
{{response.option}}
</label>
</div>
<v-btn color="info" v-bind:id="question.prev" v-if="currentQuestion > 0"
v-on:click="goToPreviousQuestion(e)" >prev</v-btn>
<v-btn color="success"
v-on:click="goToNextQuestion()">Next</v-btn>
</v-flex>
</v-form>
<child v-if="showsubchild">
</child>
</template>
<script>
import child from '../components/child'
components: {
child
}
methods: {
goToNextQuestion() {
this.showsubchild=true;
}
}
</script>
and this is my child component
<div>
<div v-if="response.inputType == 'radio'"
v-model="response.next"
class="radio radio-success"
v-bind:id="response.currentQuestion" >
<input type="radio"
v-bind:id="'child'+ response.currentQuestion"
v-bind:name="index"
v-bind:value="response.option" v-model="question.userResponses"
v-bind:checked="question.userResponses">
<label v-bind:for="'child'+ response.currentQuestion" >
{{response.option}}
</label>
</div>
<v-btn color="info"
v-on:click="prev(e)" >
prev
</v-btn>
<v-btn color="success"
v-on:click="next()">
Next
</v-btn>
<main if="showPerent"></main>
</div>
<script>
import main from '../components/survey'
export default {
name: "create",
props: ['my-props'],
components: {
main,
},
methods: {
next(){
this.showPerent=true,
}
}
}
</script>