How to access data from a loop in a vuetify carousel? - javascript

I use vuetify to make a kind of carousel to display recipes that are stored in the database.
But I would like when I click on a recipe the carousel opens below a space with all the elements of the recipe in question (the one we clicked on) So I found a component on vuetify that corresponds exactly to what I'm looking for: Here is Vuetify Carousel
But in my v-slide-item I use a loop that retrieves the recipe data but suddenly from the v-expand-transition I no longer have access to this loop how can I display the recipe data suddenly?
Here is the code :
<template>
<v-sheet
class="mx-auto"
elevation="8"
max-width="100%"
style="box-shadow: none !important;"
>
<v-slide-group
v-model="model"
class="pa-4 slider"
show-arrows
>
<v-slide-item
v-for="n in Object.keys(recipes)"
:key="recipes[n].id"
v-slot="{ active, toggle }"
>
<v-card
:color=" 'grey lighten-1'"
class="ma-4 card-recipe"
height="200"
width="200"
style="border-radius: 10px;"
v-bind:style="recipes[n].recipe[0].first_recipes_image != null ? { backgroundImage: 'url(' + recipes[n].recipe[0].first_recipes_image + ')' } : { backgroundImage: 'url(https://cdn.vuetifyjs.com/images/cards/sunshine.jpg)' }"
#click="toggle"
>
<p class="card-text" ><span class="black--text">{{ recipes[n].recipe[0].name }}</span></p>
<v-row
class="fill-height"
align="center"
justify="center"
>
<v-scale-transition>
<v-icon
v-if="active"
color="white"
size="48"
v-text="'mdi-close-circle-outline'"
></v-icon>
</v-scale-transition>
</v-row>
</v-card>
</v-slide-item>
</v-slide-group>
<v-expand-transition>
<v-sheet
v-if="model != null"
height="200"
tile
style="background-color: #FFF8F0 !important;"
>
<v-row
class="fill-height"
align="center"
justify="center"
>
<h3 class="text-h6">
Selected {{ model }}
</h3>
</v-row>
</v-sheet>
</v-expand-transition>
</v-sheet>
</template>
<script>
import { mapGetters } from "vuex";
export default {
props: {
},
data: () => ({
model: null,
recipes: [],
openedCards: [],
}),
computed: {
console: () => console,
...mapGetters({
plantActive: 'permatheque/getPlant',
}),
},
methods: {
async getPlantRecipes() {
this.$axios
.$get("/lnk/plant/recipes?plant_id=" + this.plantActive.id + "")
.then((response) => {
this.recipes = response;
console.log(this.recipes);
})
.catch((error) => {
console.log(error);
});
},
},
mounted() {
this.getPlantRecipes()
}
}
</script>
Hope I was clear enough, thanks!

You can use the v-model of the v-slide-group which is basically the index from recipes array of the selected item in the carousel.
This way you know which recipe is selected, so you can go grab the recipe info from the array or make another api call to get that info.
Example
Check this codesandbox I made: https://codesandbox.io/s/stack-71474788-recipes-carousel-6vm97o?file=/src/components/Example.vue
If you already have the recipe info within your recipes array, all you need to do is use the v-model variable of the v-slide-group which I renamed to recipeIndex to access that data directly from your array.
<v-expand-transition>
<v-sheet v-if="recipeIndex != null" tile style="background-color: #FFF3E0 !important;">
<v-container fluid class="pa-12">
<v-row>
<v-col cols="12" sm="6">
<span class="text-h6">{{ `${recipes[recipeIndex].name}'s Recipe` }}</span> <br>
<span class="text-subtitle-1">{{ recipes[recipeIndex].description }}</span>
<p class="text-justify mt-4">
{{ recipes[recipeIndex].steps }}
</p>
</v-col>
<v-col cols="12" sm="6" class="d-flex align-center justify-center">
<div class="thumbnail">
<img :src="recipes[recipeIndex].image" alt="Beach Scene" style="width: 100%;" />
</div>
</v-col>
</v-row>
</v-container>
</v-sheet>
</v-expand-transition>
If you need to get the info from a secondary api call. You can set up a watcher on the recipeIndex variable to obtain the recipe info everytime it changes.

Related

v-card is not being shown completly

I am working with vuetify and I want to implement a Stepper.
Within the stepper I want to have v-card which once clicked on read more would open. So far the functions are working.
The problem is that when I only open a card - meaning in the index.vue I put the card component instead of the stepper, the card opens reacts perfectly. But, when the card is within the stepper component, when I press on read more it is only shown a part of it. I guess some element is having a fixed size and wont resize, but I cannot figure it out where exactly the problem is. Any help is welcomed!
My index.vue file looks like this:
<template>
<v-container>
<v-app>
<div>
<Stepper/>
</div>
</v-app>
</v-container>
</template>
<script>
import Stepper from "../components/Stepper.vue";
export default {
data: () => ({
}),
components: {Stepper }
}
</script>
The Stepper.vue component looks like this:
<template>
<v-stepper v-model="e6" vertical ref="stepper">
<!--- Step 1-->
<v-stepper-step :complete="e6 > 1" step="1">
</v-stepper-step>
<v-stepper-content step="1">
<Card1 />
</v-stepper-content>
<!--- Step 2-->
<v-stepper-step :complete="e6 > 2" step="2">
</v-stepper-step>
<v-stepper-content step="2">
<Card2 />
</v-stepper-content>
<!--- Step 3-->
<v-stepper-step :complete="e6 > 3" step="3">
</v-stepper-step>
<v-stepper-content step="3">
<Card2 />
</v-stepper-content>
</v-stepper>
</template>
The cards inside are from format identical only the text is different. Hence I will post only one card:
<template>
<v-hover >
<template v-slot:default="{ hover }">
<v-card class="mx-auto">
<v-img class="white--text" src="picture1.png" width="300" height="169">
<v-card-title class="text-h5">
{{ $t('welcome_hello') }}
</v-card-title>
</v-img>
<v-card-actions>
<v-btn text color="teal accent-4" #click="openCard()">
Learn More
</v-btn>
</v-card-actions>
<v-expand-transition>
<v-card v-if="reveal" class="transition-fast-in-fast-out v-card--reveal" style="height: 100%;">
<v-card-text class="pb-0">
<p class="text-h4 text--primary">
{{ $t('welcome_message1') }}
</p>
<p>{{ $t('welcome_message2') }}</p>
<p>{{ $t('welcome_message3') }}</p>
</v-card-text>
<v-card-actions class="pt-0">
<v-btn text color="teal accent-4" #click="nextStep()">
Next
</v-btn>
</v-card-actions>
</v-card>
</v-expand-transition>
</v-card>
</template>
</v-hover>
</template>
<script>
export default {
data: () => ({
reveal: false,
}),
methods: {
openCard() {
this.reveal = true
},
closeCard() {
this.reveal = false
},
completedCard(){
},
nextStep() {
this.closeCard()
this.$root.$emit('nextStepFunction') //like this
},
}
}
</script>
<style>
.v-card--reveal {
bottom: 0;
opacity: 1 !important;
position: absolute;
width: 100%;
}
</style>
You should give your v-card a height and then overflow to scroll.
<v-card height="450" style="overflow-y: scroll; overflow-x: hidden">
// Your card body
</v-card>

Using axios to display an array in a Database

I'm having trouble using axios(my code will follow) but when i use {{response.data}} the site breaks and gives me a blank page as soon as i remove it, it works alright. I'm not too sure what I'm doing wrong, I'm quite new to using vue, vuetify and axios.
I've got a local server running for the database and the get request link works. it displays 3 columns of strings and 1 array and I'm looking to get the data from the array.
<template>
<v-app id="inspire"
style="background-color: #e4e4e4">
<!-- to be deleted-->
<v-app-bar-nav-icon style="padding-left: 80px">
<div id="app">
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">Login</router-link>
<br>
<vbtn>Logout</vbtn>
</nav>
<router-view/>
</div>
</v-app-bar-nav-icon>
<!--end-->
<!-- profiles to login to-->
<v-main style="padding: 10rem">
<v-container>
<v-row>
<v-col
v-for="n in 10"
:key="n"
cols="5"
style="background-color: #e4e4e4;">
<v-card height="200" style="background-color: #a3a3a3; text-align: center">{{n}}</v-card>
</v-col>
</v-row>
</v-container>
</v-main>
<!-- profiles to login to end-->
</v-app>
</template>
<script>
import axios from 'axios'
export default {
name: 'HelloWorld' ,
mounted () {
axios
.get("http://localhost:8081/contractor?user_id=c65722")
.then((response) => {
this.posts = response.data
})
},
data: () => ({
ecosystem: [],
importantLinks: [],
}),
methods: {}
}
</script>
'

Show mutiple v-dialog boxes with different content in vue.js

Hii I am working on the Vue.js template and I stuck at a point where I need to show dynamic v-dialog using looping statement but now it shows all.
Dom:
<template v-for="item of faq">
<div :key="item.category">
<h4>{{ item.heading }}</h4>
<div v-for="subitems of item.content" :key="subitems.qus">
<v-dialog
v-model="dialog"
width="500"
>
<template v-slot:activator="{on}">
{{subitems.qus}}
</template>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Privacy Policy
</v-card-title>
<v-card-text>
{{ subitems.ans }}
</v-card-text>
<v-divider></v-divider>
</v-card>
</v-dialog>
</div>
</div>
</template>
Script:
export default {
data: () => ({
faq,
dialog:false,
}),
}
I do not understand how I can do this. If I click on one button then it shows all.
There must a design a pattern for this one but a quick solution would be to create array of booleans for v-models of dialogs. something like below
export default {
data: () => ({
faq,
dialog: [] // Array instead of Boolean.
}),
}
and
<template v-for="item of faq">
<div :key="item.category">
<h4>{{ item.heading }}</h4>
<div v-for="(subitems, index) of item.content" :key="subitems.qus">
<v-dialog
v-model="dialog[index]"
width="500"
>
<template v-slot:activator="{on}">
{{subitems.qus}}
</template>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Privacy Policy
</v-card-title>
<v-card-text>
{{ subitems.ans }}
</v-card-text>
<v-divider></v-divider>
</v-card>
</v-dialog>
</div>
</div>
</template>
Brother, you are doing a very small mistake, you should not keep your v-dialog component inside your loop, take this out from loop block and don't take dialog as empty array keep it false.

Avatar picker with Nuxt & Vuetify

I'm having some issues to make an avatar picker works...
After click to select the avatar in not being replaced and with the error TypeError: Cannot read property 'src' of undefined at VueComponent.selectAvatar
I'm currently using Vuetify and the v-avatar component with a v-for to load all the images.
Any idea how to make it work?
HTML
<v-flex xs12 pt-0 pb-0>
<h1 class="title mb-4">User Details</h1>
<v-avatar
size="100px"
>
<img
:src="this.selectedAvatar"
alt="Avatar"
>
</v-avatar>
</v-flex>
<v-flex x12>
<v-btn
color="primary"
flat="flat"
small
#click="selectAvatarDialog = true"
class="avatar-btn"
>
Update avatar
</v-btn>
</v-flex>
<v-dialog
v-model="selectAvatarDialog"
max-width="80%"
>
<v-card>
<v-container fluid pa-2>
<v-layout row wrap align-center justify-center fill-height>
<v-flex xs6 sm4 md3 lg2 my-2 class="text-xs-center"
v-for="(avatar,i) in avatars"
:key="i">
<v-img
:src="avatar.src"
aspect-ratio="1"
width="100px"
max-width="100px"
min-width="100px"
class="dialog-avatar-img"
#click="selectAvatar()"
></v-img>
</v-flex>
</v-layout>
<v-card-actions class="mt-2">
<v-spacer></v-spacer>
<v-btn
color="primary"
flat="flat"
#click="selectAvatarDialog = false"
>
Cancel
</v-btn>
</v-card-actions>
</v-container>
</v-card>
</v-dialog>
JS
export default {
layout: 'default',
data() {
return {
selectAvatarDialog: false,
avatars: [
{src: require('#/assets/images/avatar-01.png') },
{ src: require('#/assets/images/avatar-02.png') },
{ src: require('#/assets/images/avatar-03.png') },
{ src: require('#/assets/images/avatar-04.png') },
{ src: require('#/assets/images/avatar-05.png') }
],
selectedAvatar: require('#/assets/images/avatar-01.png'),
}
},
methods: {
selectAvatar(){
this.selectedAvatar = this.avatar.src
console.log('Avatar selected')
}
}
}
Thank you
The problem is in your selectAvatar method where you are trying to use 'this.avatar' but it doesn't exist. The avatar in your for loop isn't passed to your script. You should do like this:
<v-img
...
#click="selectAvatar(i)"
></v-img>
And in your script:
methods: {
selectAvatar(i){
this.selectedAvatar = this.avatars[i].src
console.log('Avatar selected')
}
}

How to remove vuetify card on clicking a button

I have added a vuetify card and a button on it. I want that when the button is clicked, the card disappears. How can I do that?
Below is how my component looks like. I want to add a method to do so but don't know what the method will be.
<template>
<div class="notifications">
<v-layout>
<v-flex xs12 sm6 offset-sm3>
<v-card flat color="green">
<v-card-title primary-title>
<div>
<h3 class="headline">Neu Benutzer angelegt</h3>
<div> {{ card_text }} </div>
</div>
</v-card-title>
<v-card-actions>
<div class="close"><v-btn #click="removeMessage(2)">Ok</v-btn></div>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</div>
</template>
<script>
export default {
data () {
return {
card_text: 'Success!'
}
},
methods: {
removeMessage(seconds) {
},
},
};
</script>
You can hide it with v-if and a boolean flag:
<template>
<div class="notifications" v-if="show">
<v-layout>
<v-flex xs12 sm6 offset-sm3>
<v-card flat color="green">
<v-card-title primary-title>
<div>
<h3 class="headline">Neu Benutzer angelegt</h3>
<div> {{ card_text }} </div>
</div>
</v-card-title>
<v-card-actions>
<div class="close"><v-btn #click="removeMessage(2)">Ok</v-btn></div>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</div>
</template>
<script>
export default {
data () {
return {
card_text: 'Success!',
show:true;
}
},
methods: {
removeMessage(seconds) {
setTimeout(()=> this.show = false, seconds * 1000);
},
},
};
</script>
You can also use v-show and make something like this: CodePen

Categories

Resources