How can I solve [object Promise] on vue? - vue.js

My code like this :
<v-row dense>
<v-col
v-for="(item, i) in items"
:key="i"
cols="12"
>
<v-card
dark
>
<div class="d-flex flex-no-wrap justify-space-between">
<div>
<v-card-title
class="headline"
v-text="item.doctor"
></v-card-title>
<v-card-subtitle v-text="item.hospital"></v-card-subtitle>
<v-card-subtitle>{{available(item.doctorId, item.hospitalId)}}</v-card-subtitle>
</div>
<v-avatar
class="ma-3"
size="125"
tile
>
<v-img :src="item.src"></v-img>
</v-avatar>
</div>
</v-card>
</v-col>
</v-row>
methods: {
// available (doctorId, hospitalId) {
available: async function (doctorId, hospitalId) {
let fromDate = moment()
let toDate = moment().add(2, 'days')
while (fromDate <= toDate) {
const payload = {
hospitalId: hospitalId,
doctorId: doctorId,
date: fromDate.format('YYYY-MM-DD')
}
// this is async/ajax to call api by vuex store
// await this.checkAvailibility(payload)
// if (this.availibility.items.length > 0) {
if(fromDate.diff(moment(), 'days') == 0) {
return `<v-icon class="mr-2" color="success">check_circle</v-icon>Available Today`
}
else if(fromDate.diff(moment(), 'days') == 1)
return `<v-icon>check_circle</v-icon>Available Tomorrow`
else
return `<v-icon>check_circle</v-icon>Available ${fromDate}`
// }
fromDate = fromDate.add(1, 'days')
}
},
},
Demo and full code like this :
https://codepen.io/trendingnews/pen/vYENWqR?editors=1010
This error might occur because I use async. But I need that. Because I want to call ajax via vuex store
How can I solve this problem without remove async?
Note :
this.availibility.items.length is used to check whether a doctor is available or not on a certain day. if greater than 0 means it is available
I commented that because it called vuex store

Related

Vue: triggering a method when choosing another step in the stepper

Let us say that we have following steps in the stepper:
Home > Purchase > Comments > Settings
Template:
<template>
<div>
<v-card class="mb-4">
<v-card-text>
<v-select
v-model="steps"
:items="[2, 3, 4, 5, 6]"
label="# of steps"
></v-select>
</v-card-text>
</v-card>
<v-stepper v-model="e1">
<v-stepper-header>
<template v-for="n in steps">
<v-stepper-step
:key="`${n}-step`"
:complete="e1 > n"
:step="n"
editable
>
Step {{ n }}
</v-stepper-step>
<v-divider
v-if="n !== steps"
:key="n"
></v-divider>
</template>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content
v-for="n in steps"
:key="`${n}-content`"
:step="n"
>
<v-card
class="mb-12"
color="grey lighten-1"
height="200px"
></v-card>
<v-btn
color="primary"
#click="nextStep(n)"
>
Continue
</v-btn>
<v-btn text>
Cancel
</v-btn>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</div>
</template>
Script:
<script>
export default {
data() {
return {
e1: 1,
steps: 2,
}
},
watch: {
steps(val) {
if (this.e1 > val) {
this.e1 = val
}
},
},
methods: {
nextStep(n) {
if (n === this.steps) {
this.e1 = 1
} else {
this.e1 = n + 1
}
},
onLeave() {
switch (e1) {
case 1:
console.log("A")
break;
case 2:
console.log("B")
break;
case 3:
console.log("C")
break;
case 4:
console.log("D")
break;
}
},
},
} </script>
This is just a mwe. I just don't know how I trigger this method "onLeave()" as soon as I switch to another step (like clicking on Settings or something).
In my case I have a method for each of the steps which has to be triggered as soon as I leave the step for another step. I hope that makes sense.
Use the change event to trigger the function:
<v-stepper #change="onLeave($event)" v-model="e1">
...
</v-stepper>
onLeave(step) {
switch (step) {
...
}
}
See here (Vuetify docs).

Object in array is undefined in vue

I need help as the array “items1” works when “console.log(this.items1)”
However, it is undefined when “console.log(this.items1[0])”. How can I solve this? I really have no idea what is going. Ultimately, I want to gather item.text whenever user selects the tab from v-tabs. Using item.text, I am able to filter the data in db. Is there a way to gather the user input whenever user selects tab?
<template>
<v-layout>
<v-container flat grid-list-lg>
<v-layout row wrap class="flex_box feature_products">
<v-flex xs12>
<h2 class="text-xs-center feature_products_title">Check Our <span>Delicious Menu</span></h2>
</v-flex>
<v-flex xs12>
<v-card>
<v-toolbar flat>
<template v-slot:extension>
<v-tabs v-model="model" centered slider-color="yellow">
<v-tab v-for="(item, index) in items1" :key="index" :href="`#tab-${index}`">
{{ item.text }}
</v-tab>
</v-tabs>
</template>
</v-toolbar>
<v-tabs-items v-model="model">
<v-tab-item v-for="(item, index) in items1" :key="index" :value="`tab-${index}`">
<!-- your this code displays the product information, but there is no way to filter the product by category -->
<v-layout row wrap class="flex_box feature_products">
<v-flex xs12 sm3 md3 lg3 xl2 class="flex_item" v-for="(product,index) in products" :key="index">
<v-card flat v-if="product.category_name == item.text">
<v-card class="overlay_container flex_wrap pa-2">
<v-img :src="product.image" contain></v-img>
<div style="width:100%;" class="flex_bottom text-xs-center pb-2">
<h3 class="headline text-xs-center grey--text text--darken-3">{{product.item_name}}</h3>
<h4 class="grey--text text--darken-3">{{currency}}{{product.price}}</h4>
</div>
<v-card class="overlay">
<h2 style="vertical-align:middle;">{{product.item_name}}</h2>
<v-list class="details">
<v-list-tile-action>
<v-btn style="width:100%" :to="'/product/' + product.id">Details</v-btn>
</v-list-tile-action>
<v-list-tile-action>
<v-btn style="width:100%" class="main_color white--text" #click="addToCart(product)">Add To Cart</v-btn>
</v-list-tile-action>
</v-list>
</v-card>
</v-card>
</v-card>
<v-card v-else>
</v-card>
</v-flex>
</v-layout>
</v-tab-item>
</v-tabs-items>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-layout>
</template>
<script>
import Vue from 'vue'
import firebase from "firebase";
import moment from 'moment'
import db, {functions} from '#/firebase/init'
import MenuNavbar from '#/components/shop/navbar/MenuNavbar'
export default {
data(){
// Show All Categories
let ref = db.collection("item_categories");
ref.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type == "added") {
let doc = change.doc;
this.items1.push({
icon: doc.data().category_icon,
text: doc.data().category_name,
link:'CatProduct',
category:doc.data().category_name,
text1: 'Category Name: ' + doc.data().category_name
});
}
});
});
return{
model:'tab-2', // select your default tab here
currency:null,
products:[],
cart:this.$store.getters.cart,
items1:[],
}
},
components: {
MenuNavbar
},
methods: {
productInCart(product) {
const cartItems = this.cart
for (let i = 0; i < cartItems.length; i++) {
if (cartItems[i].product.id === product.id) {
return i
}
}
return null
},
addToCart(product, quantity){
const index = this.productInCart(product)
const productQuantity = (!quantity || quantity < 1) ? 1 : parseInt(quantity)
if (index === null) {
var items = {
product: product,
quantity: productQuantity
}
//this.$store.commit('catalog/updateCart', items)
this.$store.commit('updateCart', items)
}else {
if(!quantity){
// If item is already into the cart then add++ quantity
this.$store.commit('increaseQuantity', index)
}else{
// When quantity updated manually
}
}
},
removeCart(index){
this.$store.commit('removeCart', index)
},
},
computed:{
counter(){
return this.$store.getters.counter
},
},
getTabText(text){
return text
},
created(){
var db = firebase.firestore();
// Current Currency
db.collection("settings").doc('config').onSnapshot(doc =>{
this.currency = doc.data().currency
})
console.log(this.items1[0])
// Show All Items
let cref = db.collection('items').orderBy('timestamp', 'desc').where("featured", "==", true)
cref.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if(change.type == 'added'){
let doc = change.doc
this.products.push({
id:doc.id,
item_name:doc.data().item_name,
image:doc.data().image,
category_name:doc.data().item_category,
price:doc.data().price,
quantity:doc.data().quantity,
timestamp:moment(doc.data().timestamp).fromNow('lll')
})
}
})
})
}
}
</script>

Why my Vuetify's Datepicker doesn't work?

I'm new to vuejs + vuetify. I am using a datepicker to filter a datatable. The filtering part is working, however, when I clear the field the table does not return to original form. I tested using the html's input-date and worked perfectly. What am I doing wrong?
This is the datepicker component:
<template>
<v-menu
ref="menu"
v-model="menu"
:close-on-content-click="false"
transition="scale-transition"
offset-y
max-width="290"
min-width="290"
>
<template v-slot:activator="{ on }">
<v-text-field
clearable
dense
color="#15C98A"
outlined
v-model="computedDataFormatada"
label="data inicio"
append-icon="mdi-calendar-outline"
readonly
v-on="on"
></v-text-field>
</template>
<v-date-picker
v-model="date"
#input="dataEscolhida"
locale="pt"
color="#15C98A"
no-title
></v-date-picker>
</v-menu>
</template>
<script>
export default {
name:'DataPicker',
props:['label'],
data() {
return {
date: null,
menu: false,
};
},
computed: {
computedDataFormatada () {
return this.formataData(this.date)
},
},
methods: {
dataEscolhida() {
this.$emit('selecionado',this.computedDataFormatada);
this.menu = false;
},
formataData(date) {
if (!date) return null;
const [year, month, day] = date.split("-");
return `${day}/${month}/${year}`;
}
}
};
</script>
This is the way I'm filtering:
<v-data-table
fixed-header
single-select
item-key="id"
:headers="headers"
:items="customFilter"
:items-per-page="5"
class="elevation-1"
></v-data-table>
computed:{
customFilter(){
let startDate = this.dataInicioFiltro;
let endDate = this.dataFimFiltro;
return _.filter(this.grupos, (function (info) {
let date = info.data;
if ( (_.isNull(startDate) && _.isNull(endDate))||(_.isEmpty(startDate) && _.isEmpty(endDate)))
return true;
else if((!_.isEmpty(startDate) && _.isEmpty(endDate)))
return date ===startDate;
else if((_.isEmpty(startDate) && !_.isEmpty(endDate)))
return date ===endDate;
else
return (date >= startDate && date <= endDate);
}))
}
}
And this is how I'm using the component in the view:
<data-filtro label="data inicial" #selecionado="dataInicioFiltro=$event" />
I'm also using the lib lodash.
Ok everyone, I finally solved it out! Just have to use the event click:clear

Adding more than 1 field in v-for is causing an infinite loop

I am trying to add a payment form for the user to fill out of field.type === 'payment'. However, when I add more than one field to add inside of the v-for loop, I get a “You may have an infinite update loop in a component render function.” error. What can I do to avoid this? Here is a snippet of what I'm trying to do
<div v-for="(field, key) in page.fields" :key="key">
<v-row v-if="field.type === 'payment'">
<v-col cols="12" sm="8">
<v-text-field //ADDING THIS FIELD BY ITSELF WORKS FINE
label="Card Number"
prepend-inner-icon="credit_card"
v-model="card_number"
/>
</v-col>
<v-col cols="12" sm="4">
<v-text-field //WHEN I TRY TO ADD IN THIS FIELD, THE LOOP ERROR OCCURS
label="CVV"
v-model="cvv"
/>
</v-col>
</v-row>
</div>
<script>
computed: {
...mapGetters('formbuilder', ['form'])
},
watch: {
form(newVal) {
this.page = newVal;
}
},
data() {
return {
cvv: '',
card_number: '',
page: {}
}
}
</script>

Vue components data and methods disappear on one item when rendered with v-for as Vuetify's cards

I have Vue component that renders a list of Vuetify cards:
<restaurant-item
v-for="card in userRestaurantCards"
:key="card['.key']"
:card="card"
>
</restaurant-item>
The card displays info obtained from props, Vuex, as well as info defined in the restaurant-item card itself:
<v-card>
<v-img
class="white--text"
height="200px"
:src="photo"
>
<v-container fill-height fluid class="card-edit">
<v-layout fill-height>
<v-flex xs12 align-end flexbox>
<v-menu bottom right>
<v-btn slot="activator" dark icon>
<v-icon>more_vert</v-icon>
</v-btn>
<v-list>
<edit-restaurant-dialog :card="card" :previousComment="comment"></edit-restaurant-dialog>
<v-list-tile >
<v-list-tile-title>Delete</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</v-flex>
</v-layout>
</v-container>
</v-img>
<v-card-title>
<div>
<span class="grey--text">Friends rating: {{ card.rating }}</span><br>
<h3>{{ card.name }}</h3><br>
<span>{{ card.location }}</span>
</div>
</v-card-title>
<v-card-actions>
<v-btn flat color="purple">Comments</v-btn>
<v-spacer></v-spacer>
<v-btn icon #click="show = !show">
<v-icon>{{ show ? 'keyboard_arrow_down' : 'keyboard_arrow_up' }}</v-icon>
</v-btn>
</v-card-actions>
<v-slide-y-transition>
<v-card-text v-show="show">
<div> {{ comment.content }} </div>
</v-card-text>
</v-slide-y-transition>
</v-card>
The script is:
import { find, isEmpty } from 'lodash-es'
import { mapGetters } from 'vuex'
import EditRestaurantDialog from '#/components/dashboard/EditRestaurantDialog'
export default {
name: 'restaurant-item',
components: {
EditRestaurantDialog
},
props: {
card: Object
},
data() {
return {
show: false,
name: this.card.name,
location: this.card.location,
rating: this.card.rating,
link: this.card.link,
photo: this.getPhotoUrl()
}
},
computed: {
comment() {
// Grab the content of the comment that the current user wrote for the current restaurant
if (isEmpty(this.card.comments)) {
return { content: 'You have no opinions of this place so far' }
} else {
const userComment = find(this.card.comments, o => o.uid === this.currentUser)
return userComment
}
},
...mapGetters(['currentUser'])
},
methods: {
getPhotoUrl() {
const cardsDefault = find(this.card.photos, o => o.default).url
if (isEmpty(cardsDefault)) {
return 'https://via.placeholder.com/500x200.png?text=No+pics+here+...yet!'
} else {
return cardsDefault
}
}
}
}
Here is the kicker: when I have 2 objects in the data, the first card component renders correctly... while the second doesn't have any of the methods or data defined right there in the script.
Here's a link to a screenshot of the Vue Devtools inspecting the first card:
https://drive.google.com/file/d/1LL4GQEj0S_CJv55KRgJPHsCmvh8X3UWP/view?usp=sharing
Here's a link of the second card:
https://drive.google.com/open?id=13MdfmUIMHCB_xy3syeKz6-Bt9R2Yy4Xe
Notice how the second one has no Data except for the route?
Also, note that both components loaded props, vuex bindings and computed properties just as expected. Only the Data is empty on the second one...
I've been scratching my head for a while over this. Any ideas would be more than welcome.
I got it to work after I moved the method getPhotoUrl method to a computed property:
computed: {
comment() {
// Grab the content of the comment that the current user wrote for the current restaurant
if (isEmpty(this.card.comments)) {
return { content: 'You have no opinions of this place so far' }
} else {
const userComment = find(this.card.comments, o => o.uid === this.currentUser)
return userComment
}
},
photoUrl() {
const cardsDefault = find(this.card.photos, o => o.default)
if (isEmpty(cardsDefault)) {
return 'https://via.placeholder.com/500x200.png?text=No+pics+here+...yet!'
} else {
return cardsDefault.url
}
},
...mapGetters(['currentUser'])
}