'When using Vuetify's v-menu, only the first click of the menu is displayed
What I want to solve
I am using Vuetify to create my calendar. I use a combination of drag and drop and event clicking. I added the Vuetify v-menu so that I can change the color of the event in the popup that appears when clicked. When the button is clicked, the popup to change the color appears. However, the v-menu that I added only responds to the first event, and closes when the button is pressed on the second event. How can I solve this problem? By the way, no error is shown.
Code
Calendar
<template>
<v-row class="fill-height">
<v-col>
<v-sheet height="600">
<v-calendar
ref="calendar"
v-model="value"
color="primary"
type="week"
:events="events"
:event-color="getEventColor"
:event-ripple="false"
locale="ja-jp"
:day-format="(timestamp) => new Date(timestamp.date).getDate()"
:month-format="(timestamp) => (new Date(timestamp.date).getMonth() + 1) + ' /'"
@change="getEvents"
@mousedown:event="startDrag"
@click:event="showEvent"
@mousedown:time="startTime"
@mousemove:time="mouseMove"
@mouseup:time="endDrag"
@mouseleave.native="cancelDrag"
>
<template #event="{ event, timed, eventSummary }">
<div
class="v-event-draggable"
v-html="eventSummary()"
/>
<div
v-if="timed"
class="v-event-drag-bottom"
@mousedown.stop="extendBottom(event)"
/>
// A pop-up will appear when you click on it.
////////////////////////////////////////////////////////////////////
<!-- Show popup when clicked -->
<v-menu
v-model="selectedOpen"
:close-on-content-click="false"
:activator="selectedElement"
offset-x
>
<v-card
color="grey lighten-2"
min-width="350px"
flat
>
<v-toolbar>
<v-btn icon>
<v-icon>mdi-pencil</v-icon>
</v-btn>
<v-toolbar-title v-html="selectedEvent.name" />
<v-spacer />
<!-- Color Change Botan -->
<div class="text-center">
<v-menu offset-y>
<template #activator="{ on, attrs }">
<v-btn
icon
v-bind="attrs"
v-on="on"
>
<v-icon
:color="selectedEvent.color"
>
mdi-brightness-1
</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(color, index) in colors"
:key="index"
>
<v-icon
:color="color"
@click="changeColor(color)"
>
mdi-brightness-1
</v-icon>
</v-list-item>
</v-list>
</v-menu>
</div>
////////////////////////////////////////////////////////////////////////////////////
<v-btn icon>
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<span v-html="selectedEvent.details" />
</v-card-text>
<v-card-actions>
<v-btn
text
color="secondary"
@click="selectedOpen = false"
>
Cancel
</v-btn>
</v-card-actions>
</v-card>
</v-menu>
<!-- -->
</template>
</v-calendar>
</v-sheet>
</v-col>
</v-row>
</template>
<script>
import '@/assets/css/schedule.scss'
export default {
data: () => ({
value: '',
events: [],
colors: ['#2196F3', '#3F51B5', '#673AB7', '#00BCD4', '#4CAF50', '#FF9800', '#757575'],
names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party'],
dragEvent: null,
dragStart: null,
createEvent: null,
createStart: null,
extendOriginal: null,
selectedElement: null,
selectedOpen: false,
selectedEvent: {},
menu: false
}),
methods: {
startDrag ({ event, timed }) {
if (event && timed) {
this.dragEvent = event
this.dragTime = null
this.extendOriginal = null
}
},
startTime (tms) {
const mouse = this.toTime(tms)
if (this.dragEvent && this.dragTime === null) {
const start = this.dragEvent.start
this.dragTime = mouse - start
} else {
this.createStart = this.roundTime(mouse)
this.createEvent = {
name: 'event',
color: '#2196F3',
start: this.createStart,
end: this.createStart,
timed: true
}
this.events.push(this.createEvent)
}
},
extendBottom (event) {
this.createEvent = event
this.createStart = event.start
this.extendOriginal = event.end
},
mouseMove (tms) {
const mouse = this.toTime(tms)
if (this.dragEvent && this.dragTime !== null) {
const start = this.dragEvent.start
const end = this.dragEvent.end
const duration = end - start
const newStartTime = mouse - this.dragTime
const newStart = this.roundTime(newStartTime)
const newEnd = newStart + duration
this.dragEvent.start = newStart
this.dragEvent.end = newEnd
} else if (this.createEvent && this.createStart !== null) {
const mouseRounded = this.roundTime(mouse, false)
const min = Math.min(mouseRounded, this.createStart)
const max = Math.max(mouseRounded, this.createStart)
this.createEvent.start = min
this.createEvent.end = max
}
},
endDrag () {
this.dragTime = null
this.dragEvent = null
this.createEvent = null
this.createStart = null
this.extendOriginal = null
},
cancelDrag () {
if (this.createEvent) {
if (this.extendOriginal) {
this.createEvent.end = this.extendOriginal
} else {
const i = this.events.indexOf(this.createEvent)
if (i !== -1) {
this.events.splice(i, 1)
}
}
}
this.createEvent = null
this.createStart = null
this.dragTime = null
this.dragEvent = null
},
roundTime (time, down = true) {
const roundTo = 15 // minutes
const roundDownTime = roundTo * 60 * 1000
return down
? time - time % roundDownTime
: time + (roundDownTime - (time % roundDownTime))
},
toTime (tms) {
return new Date(tms.year, tms.month - 1, tms.day, tms.hour, tms.minute).getTime()
},
// edit
showEvent ({ nativeEvent, event }) {
const open = () => {
this.selectedEvent = event
this.selectedElement = nativeEvent.target
requestAnimationFrame(() => requestAnimationFrame(() => { this.selectedOpen = true }))
}
if (this.selectedOpen) {
this.selectedOpen = false
requestAnimationFrame(() => requestAnimationFrame(() => open()))
} else {
open()
}
nativeEvent.stopPropagation()
},
rnd (a, b) {
return Math.floor((b - a + 1) * Math.random()) + a
},
rndElement (arr) {
return arr[this.rnd(0, arr.length - 1)]
},
changeColor (color) {
this.selectedEvent.color = color
}
}
}
</script>
What I've tried.
・I thought it was caused by the v-slot:activator, so I checked it out. As a result, I found out that on has a function to display a popup, but I couldn't find the relevance of this.
Solution 1:[1]
In the default configuration of Vuetify, the popup display was controlled by v-model, but I was able to solve this problem by binding with :value.
<!-- Show popup when clicked -->
<v-menu
"selectedOpen"
:value="selectedOpen"
:close-on-content-click="false"
:activator="selectedElement"
offset-x
>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ke kaji |
