Positional problems with vuetify speed dial - vue.js

I am wanting to use the vuetify speeddial component in my app, but I am getting wierd positioning errors, what I am wanting is the button to be clicked and then the additional options slide to the left of it,
As you can see from the image above they are positioned on the left but far to far from the original "parent" button, I have attemped to make a codesandbox but the results are inconclusive.
https://codesandbox.io/s/vuetify-playground-forked-gwtkc?file=/src/components/SpeedDial.vue
And finally here is my component code,
<template>
<v-speed-dial
v-model="fab"
direction="left"
transition="slide-x-reverse-transition"
>
<template v-slot:activator>
<v-btn
v-model="fab"
color="blue darken-2"
dark
fab
>
<v-icon v-if="fab">mdi-close</v-icon>
<v-icon v-else>mdi-account-circle</v-icon>
</v-btn>
</template>
<v-btn fab dark small color="green">
<v-icon>mdi-pencil</v-icon>
</v-btn>
<v-btn fab dark small color="indigo">
<v-icon>mdi-plus</v-icon>
</v-btn>
<v-btn fab dark small color="red">
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-speed-dial>
</template>
<script>
export default {
name: 'QuickSpeedDial',
data() {
return {
fab: false,
tabs: null
}
},
computed: {
activeFab () {
switch (this.tabs) {
case 'one': return { class: 'purple', icon: 'account_circle' }
case 'two': return { class: 'red', icon: 'edit' }
case 'three': return { class: 'green', icon: 'keyboard_arrow_up' }
default: return {}
}
},
}
}
</script>

You need to add a style as it says on the official website.
...
<style>
.v-speed-dial {
position: absolute;
}
.v-btn--floating {
position: relative;
}
</style>
...

Related

Vue/Vuetify - breakpoints based on component size

As far as I can see, Vuetify allows you to define breakpoints based on viewport size. Is it also possible to define breakpoints based on the size of the component? E.g.
when several components are shown on an overview page, it would use a more "compact" layout to be able to show the components side by side on large screens.
when only one component is shown it could take up more space (on large screens).
the "compact" layout could also be used when only one component is shown on a small screen.
on small screens, the overview page could show several components vertically rather than side by side.
Or can you recommend a better approach to this?
As far as I know, there is no such feature in Vuetify. However, you can always hide v-col containing the component and other columns will take up the freed-up space.
For example:
https://codepen.io/olegnaumov/pen/rNpzvEX
Since you cannot rely on global breakpoints (at least for changes based on the number of components), you can pass your component a layout prop that dictates the internal layout of the component.
Widget component
<template>
<div>
<div>Widget</div>
<v-row :class="{ 'flex-column': layout === 'vertical' }">
<v-col> Column 1 </v-col>
<v-col> Column 2 </v-col>
<v-col v-if="layout !== 'compact'"> Column 3 </v-col>
<v-col v-if="layout !== 'compact'"> Column 4 </v-col>
</v-row>
</div>
</template>
<script>
export default {
name: "Widget",
props: {
layout: {
type: String,
default: "normal", // Options: ['normal', 'vertical', 'compact']
},
},
};
</script>
Then, you can make use of two directives provided by Vuetify to compute the layout of the child components and parent container: v-mutate to watch for changes in the number of children (using the child modifier) and v-resize to watch for resize of the app.
Parent component
<template>
<v-app v-resize="onResize">
<v-container fluid>
<v-row
ref="widget_container"
v-mutate.child="onMutate"
:class="{ 'flex-column': layout_container === 'vertical' }"
>
<template v-for="n in show">
<v-col :key="n">
<widget :layout="layout_widget"></widget>
</v-col>
</template>
</v-row>
</v-container>
</v-app>
</template>
<script>
import Widget from "/src/components/widget.vue";
export default {
name: "App",
components: {
Widget,
},
data() {
return {
show: 2, // Any other method to change the number of widgets shown
// See the codesanbox for one of them
container_width: null,
widget_width: null,
// Tweak below values accordingly
container_breackpoints: {
400: "vertical",
900: "normal",
},
widget_breackpoints: {
200: "compact",
500: "normal",
},
};
},
computed: {
layout_container() {
let breackpoint = Object.keys(this.container_breackpoints)
.sort((a, b) => b - a)
.find((k) => this.container_width > k);
return this.container_breackpoints[breackpoint] || "normal";
},
layout_widget() {
if (this.layout_container === "vertical") return "vertical";
let breackpoint = Object.keys(this.widget_breackpoints)
.sort((a, b) => b - a)
.find((k) => this.widget_width > k);
return this.widget_breackpoints[breackpoint] || "normal";
},
},
methods: {
setLayout() {
this.container_width = this.$refs.widget_container.clientWidth;
this.widget_width =
this.container_width / this.$refs.widget_container.children.length;
},
onMutate() {
this.setLayout();
},
onResize() {
this.setLayout();
},
},
};
</script>
Note, this is not a production-ready solution, but rather a proof of concept showing the use of v-mutate and v-resize for this purpose.
You can see this Codesanbox for demonstration.
You can write your own, using useResizeObserver and applying size classes on the element, which can in turn be used to modify the CSS rules to itself and its descendants:
Example:
const { createApp, ref } = Vue;
const { createVuetify } = Vuetify;
const vuetify = createVuetify();
const { useResizeObserver } = VueUse;
const app = createApp({
setup() {
const el = ref(null)
const size = ref('')
useResizeObserver(el, (entries) => {
const { width } = entries[0].contentRect;
size.value =
width < 600
? "xs"
: width < 960
? "sm"
: width < 1264
? "md"
: width < 1904
? "lg"
: "xl";
});
return { el, size };
},
});
app.use(vuetify).mount("#app");
.xs span {
color: orange;
}
.sm span {
color: red;
}
.md span {
color: blue;
}
.lg span {
color: green;
}
<script src="https://cdn.jsdelivr.net/npm/vue#3.2.45/dist/vue.global.prod.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#3.1.1/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#3.1.1/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/#vueuse/shared"></script>
<script src="https://unpkg.com/#vueuse/core"></script>
<div id="app">
<v-app>
<v-main class="h-100">
<v-row no-gutters class="h-100" style="background: #f5f5f5">
<v-col
class="h-100"
cols="12"
sm="6"
lg="9"
>
<v-card class="h-100 pa-2" :class="size" ref="el">
v-card: {{ size }} <br>
window:
<span class="d-inline-block d-sm-none">xs</span>
<span class="d-none d-sm-inline-block d-md-none">sm</span>
<span class="d-none d-md-inline-block d-lg-none">md</span>
<span class="d-none d-lg-inline-block d-xl-none">lg</span>
<span class="d-none d-xl-inline-block">xl</span>
</v-card>
</v-col>
</v-row>
</v-main>
</v-app>
</div>

Vuetify toggle between light and dark theme (with vuex)

so in my Vue-project I basically have two pages/components that will be shown with the use of vue-router depending on the URL. I can switch between those pages/components via a button.
I am also using VueX for the management of some data.
Now I included a switch in one of the components to toggle between a dark and a light theme from Vuetify.
In the template for this component I do:
<v-switch
label="Toggle dark them"
#change="toggleDarkTheme()"
></v-switch>
And in the function that gets called I do:
toggleDarkTheme() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
console.log(this.$vuetify.theme.dark);
},
In app.vue I have included the <v-app dark> and in my main.js i have the following:
Vue.use(Vuetify);
const vuetify = new Vuetify({
theme: {
// dark: true,
themes: {
light: {
primary: colors.purple,
secondary: colors.grey.darken1,
accent: colors.shades.black,
error: colors.red.accent3,
background: colors.indigo.lighten5,
},
dark: {
primary: colors.blue.lighten3,
background: colors.indigo.base,
},
},
},
});
Vue.config.productionTip = false;
new Vue({
router,
store,
vuetify,
render: (h) => h(App),
}).$mount('#app');
So my problem now is, when I click the switch, the theme is indeed toggled from light to dark mode in this component. Light mode is the default and when I click the switch once, I get dark theme. However when I click the button to switch to the other URL, there the light theme will be used.
How do I implement this feature correctly?
Thanks in advance!
You should have a JavaScript class called vuetify.js, that should look like this in your case.
import Vue from "vue";
import Vuetify from "vuetify/lib";
Vue.use(Vuetify);
export default new Vuetify({
theme: {
themes: {
light: {
primary: colors.purple,
secondary: colors.grey.darken1,
accent: colors.shades.black,
error: colors.red.accent3,
background: colors.indigo.lighten5
},
dark: {
primary: colors.blue.lighten3,
background: colors.indigo.base
}
}
}
});
Your switch should be working, but just in case, try this button I've made in your component.
<div>
<v-tooltip v-if="!$vuetify.theme.dark" bottom>
<template v-slot:activator="{ on }">
<v-btn v-on="on" color="info" small fab #click="darkMode">
<v-icon class="mr-1">mdi-moon-waxing-crescent</v-icon>
</v-btn>
</template>
<span>Dark Mode On</span>
</v-tooltip>
<v-tooltip v-else bottom>
<template v-slot:activator="{ on }">
<v-btn v-on="on" color="info" small fab #click="darkMode">
<v-icon color="yellow">mdi-white-balance-sunny</v-icon>
</v-btn>
</template>
<span>Dark Mode Off</span>
</v-tooltip>
</div>
The Button calls this method in your <script>
darkMode() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
}
The below code creates a dark mode toggle switch btn.
Note: Its use Localstore
DarkModeToggel.vue
<template>
<v-icon class="mr-2">
mdi-brightness-4
</v-icon>
<v-list-item-title class="pr-10">
Dark Mode
</v-list-item-title>
<v-switch v-model="darkmode" color="primary" />
</template>
--
<script>
export default {
data () {
return {
darkmode: false
}
},
watch: {
darkmode (oldval, newval) {
this.handledarkmode()
}
},
created () {
if (process.browser) {
if (localStorage.getItem('DarkMode')) {
const cookieValue = localStorage.getItem('DarkMode') === 'true'
this.darkmode = cookieValue
} else {
this.handledarkmode()
}
}
},
methods: {
handledarkmode () {
if (process.browser) {
if (this.darkmode === true) {
this.$vuetify.theme.dark = true
localStorage.setItem('DarkMode', true)
} else if (this.darkmode === false) {
this.$vuetify.theme.dark = false
localStorage.setItem('DarkMode', false)
}
}
}
}
}
</script>
#ckuessner answer is working but not persistent.
Button theme switcher with persistence of dark theme state in cookies based on solution of #rohit-nishad.
NPM package used for cookies reading/writing: 'cookie-universal-nuxt'.
ColorThemeSwitch.vue
<template>
<v-tooltip bottom>
<template #activator="{ on }">
<v-btn v-on="on" icon #click="switchTheme">
<v-icon>
{{ $vuetify.theme.dark ? 'mdi-white-balance-sunny' : 'mdi-moon-waxing-crescent' }}
</v-icon>
</v-btn>
</template>
<span>Change theme</span>
</v-tooltip>
</template>
<script>
export default {
created() {
const darkModeCookie = this.$cookies.get('app.darkMode');
if (darkModeCookie) {
this.$vuetify.theme.dark = darkModeCookie;
}
},
methods: {
switchTheme() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
this.$cookies.set('app.darkMode', this.$vuetify.theme.dark);
},
},
};
</script>
It is better to put the code from 'created' hook somewhere in layouts or plugin so your app will change the theme no matter if component is presented on the current page. Example for plugin:
~/plugins/persistedThemeLoader.js
export default function ({ $vuetify, $cookies }) {
const darkModeCookie = $cookies.get('app.darkMode');
if (darkModeCookie) {
$vuetify.theme.dark = darkModeCookie;
}
}
nuxt.config.js
plugins: [
'~/plugins/vuetify',
{ src: '~/plugins/persistedThemeLoader', mode: 'client' },
],

vue clicking on the action button's focus area breaks it

I'm trying to create a floating action button by using vuetify -vspeed dial. I created a logic to style my button whenever it's clicked and it's working perfect, it collapses and expands whenever i click on it. However, if i try to click the focus area of the action buttons, it breaks it and close the buttons. How can i prevent that? When I click on button, it's fine - I use click.stop to make it persistent but if i click to the area right next to button, it closes the buttons which breaks my logic for styling. Here's my code
Test.Vue
<template>
<v-card :class="{create: backgroundColor }">
<v-speed-dial
:bottom="true"
:right="true"
:direction="direction"
:transition="transition"
fixed
>
<template v-slot:activator>
<v-btn
:class="{is_active:isActive}"
color="#C6002B"
fab
dark
#click=toggleButton
x-large
>
<v-icon>{{isActive? 'mdi-close' : 'mdi-account-circle'}}</v-icon><span>{{isActive ? "EXPANDED" : ''}}</span>
</v-btn>
</template>
<v-btn
v-if="finalProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func1')"
color="white" >
<v-icon color="#F0BE85">mdi-pencil</v-icon>
</v-btn>
<v-btn
v-if="thirdProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func2')"
color="white">
>
<v-icon color="purple">mdi-delete</v-icon>
</v-btn>
<v-btn
:class="{alignLeft:isActive}"
v-if="secondProp"
fab
dark
large
#click.stop="$emit('func3')"
color="white">
>
<v-icon color="green">mdi-plus</v-icon>
</v-btn>
<v-btn
v-if="firstProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func4')"
color="white">
>
<v-icon color="red">home</v-icon>
</v-btn>
</v-speed-dial>
</v-card>
</template>
<script>
export default {
name: 'FloatingButton',
props: {
firstProp: Boolean,
secondProp: Boolean,
thirdProp: Boolean,
finalProp: Boolean
},
data: () => ({
direction: 'top',
fab: false,
right: true,
bottom: true,
transition: 'scale-transition',
isActive: false,
backgroundColor: false,
check:true
}),
methods: {
toggleButton:function() {
this.isActive = !this.isActive
this.backgroundColor = !this.backgroundColor
}
},
}
</script>
<style scoped>
.is_active {
min-width:120px
/* width: 380px;
height: 70px;
border-radius: 36px;
margin:5px; */
}
.is_active span {
font-size: 18px;
letter-spacing: 0px;
}
.create {
min-width: 100%;
min-height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 4;
background:rgba(0,0,0,0.4);
color:rgba(0,0,0,0.8);
}
}
</style>
App. vue
<template>
<v-app>
<Test :firstProp=a :secondProp=b :thirdProp=c :lastProp=d />
</v-app>
</template>
<script>
import Test from './components/Test'
export default {
name: 'App',
components: {
Test
},
data(){
return{
a:true,
b:true,
c:true,
d:true
}
}
};
</script>
I don't see what's wrong. Can you check this reproduction? I mostly only changed the casing of attributes on <Test> element.
Vue.component('Test', {
template: `
<v-card :class="{create: backgroundColor }">
<v-speed-dial
:bottom="true"
:right="true"
:direction="direction"
:transition="transition"
fixed
>
<template v-slot:activator>
<v-btn
:class="{is_active:isActive}"
color="#C6002B"
fab
dark
#click="toggleButton"
x-large
>
<v-icon>{{isActive? 'mdi-close' : 'mdi-account-circle'}}</v-icon>
</v-btn>
</template>
<v-btn
v-if="finalProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func1')"
color="white" >
<v-icon color="#F0BE85">mdi-pencil</v-icon>
</v-btn>
<v-btn
v-if="thirdProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func2')"
color="white">
>
<v-icon color="purple">mdi-delete</v-icon>
</v-btn>
<v-btn
:class="{alignLeft:isActive}"
v-if="secondProp"
fab
dark
large
#click.stop="$emit('func3')"
color="white">
>
<v-icon color="green">mdi-plus</v-icon>
</v-btn>
<v-btn
v-if="firstProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func4')"
color="white">
>
<v-icon color="red">home</v-icon>
</v-btn>
</v-speed-dial>
</v-card>
`,
props: {
firstProp: Boolean,
secondProp: Boolean,
thirdProp: Boolean,
finalProp: Boolean
},
data: () => ({
direction: 'top',
fab: false,
right: true,
bottom: true,
transition: 'scale-transition',
isActive: false,
backgroundColor: false,
check:true
}),
methods: {
toggleButton: function() {
this.isActive = !this.isActive
this.backgroundColor = !this.backgroundColor
}
},
})
Vue.config.productionTip = false
new Vue({
el: '#app',
vuetify: new Vuetify(),
data(){
return{
a:true,
b:true,
c:true,
d:true
}
}
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<style scoped>
.is_active {
/*min-width:120px
width: 380px;
height: 70px;
border-radius: 36px;
margin:5px; */
}
.is_active span {
font-size: 18px;
letter-spacing: 0px;
}
.create {
min-width: 100%;
min-height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 4;
background:rgba(0,0,0,0.4);
color:rgba(0,0,0,0.8);
}
}
</style>
</head>
<body>
<div id="app">
<v-app>
<Test :first-prop="a" :second-prop="b" :third-prop="c" :last-prop="d" />
</v-app>
</div>
</body>
</html>

vuetify tabs component doesnt work correctly with flex animation

I'm trying to get the v-tabs to work with my expand menu.
Basically when I click the toggle open, the right side menu will slide out, and inside this menu I want to use the tabs component from vuetify.
It doesn't seem to work, when clicking on the tabs, it's jumping all over the places.
It starts to work correctly when I resize the window manually. Any help please?
Here's the codepen
codepen.io/anon/pen/WmKQLp
You should be able to use a Navigation Drawer without any custom styling needed... (Vuetify has built in components for what you're trying to accomplish)..
Here is a 'quick and dirty' pseudo example showing how you can accomplish this:
Codepen Example can be found here. updated with resizing ability
EDIT:
If you did want to use your custom CSS, you will need to add an additional custom CSS class - this is happening because of the translate, among other Vuetify styles conflicting with your custom CSS...
As outlined here, add this class: (I highly advise against doing this)
.v-tabs__container {
transform: translateX(0px)!important;
}
HTML
<div id="app">
<v-app>
<v-navigation-drawer app right width="550" v-model="navigation.shown">
<v-toolbar color="primary">
<v-toolbar-title class="headline text-uppercase">
<span>t a</span><span class="font-weight-light"> B S </span>
</v-toolbar-title>
</v-toolbar>
<v-tabs>
<v-tab v-for="n in 3" :key="n">
Item {{ n }}
</v-tab>
<v-tab-item v-for="n in 3" :key="n">
<v-card flat>
<v-card-text>Content for tab {{ n }} would go here</v-card-text>
</v-card>
</v-tab-item>
</v-tabs>
</v-navigation-drawer>
<v-layout justify-center>
<v-btn #click="navigation.shown = !navigation.shown">Toggle {{ direction }}</v-btn>
</v-layout>
</v-app>
</div>
JS/Vue
new Vue({
el: "#app",
data: () => {
return {
navigation: {
shown: false,
}
};
},
computed: {
direction() {
return this.navigation.shown === false ? "Open" : "Closed"
}
},
});
EDIT: (with resizing ability)
HTML:
<div id="app">
<v-app>
<v-navigation-drawer
ref="drawer"
app
right
:width="navigation.width"
v-model="navigation.shown"
>
<v-toolbar color="primary">
<v-toolbar-title class="headline text-uppercase">
<span>t a</span><span class="font-weight-light"> b s </span>
</v-toolbar-title>
</v-toolbar>
<v-tabs>
<v-tab v-for="n in 3" :key="n">
Item {{ n }}
</v-tab>
<v-tab-item v-for="n in 3" :key="n">
<v-card flat>
<v-card-text>Content for tab {{ n }} would go here</v-card-text>
</v-card>
</v-tab-item>
</v-tabs>
</v-navigation-drawer>
<v-layout justify-center>
<v-btn #click="navigation.shown = !navigation.shown">Toggle {{ direction }}</v-btn>
</v-layout>
</v-app>
</div>
JS/Vue:
new Vue({
el: "#app",
data: () => {
return {
navigation: {
shown: false,
width: 550,
borderSize: 3
}
};
},
computed: {
direction() {
return this.navigation.shown === false ? "Open" : "Closed";
}
},
methods: {
setBorderWidth() {
let i = this.$refs.drawer.$el.querySelector(
".v-navigation-drawer__border"
);
i.style.width = this.navigation.borderSize + "px";
i.style.cursor = "ew-resize";
},
setEvents() {
const minSize = this.navigation.borderSize;
const el = this.$refs.drawer.$el;
const drawerBorder = el.querySelector(".v-navigation-drawer__border");
const vm = this;
const direction = el.classList.contains("v-navigation-drawer--right")
? "right"
: "left";
function resize(e) {
document.body.style.cursor = "ew-resize";
let f = direction === "right"
? document.body.scrollWidth - e.clientX
: e.clientX;
el.style.width = parseInt(f) + "px";
}
drawerBorder.addEventListener(
"mousedown",
function(e) {
if (e.offsetX < minSize) {
el.style.transition = "initial";
document.addEventListener("mousemove", resize, false);
}
},
false
);
document.addEventListener(
"mouseup",
function() {
el.style.transition = "";
vm.navigation.width = el.style.width;
document.body.style.cursor = "";
document.removeEventListener("mousemove", resize, false);
},
false
);
}
},
mounted() {
this.setBorderWidth();
this.setEvents();
}
});

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'])
}