I'm trying to integrate cytoscape into a vuetify SPA. Rendering a graph into a v-card-element is already working. What is also working is an on-click handler to navigate to a different page using the vue router when clicking a note in the graph. But when I replace the router-push with a command to open a context menu (v-menu), the context-menu never appears. I already double checked that the same context menu appears if triggered from a different place in the vue page.
Opening the context menu is implemented with a simple boolean value registered in vue which is bound to the v-model of the v-menu. By setting the value to true the context menu should open.
But that never happens when the value is set to true from within the cytoscape on-click handler.
The code is partially copied from the vuetify examples.
Here is the template:
<template>
<v-container fluid>
<v-layout row justify-center align-center>
<v-flex xs10>
<v-card>
<v-toolbar>
<v-btn @click="contextMenuOpen=true">Show Contextmenu</v-btn>
</v-toolbar>
<div ref="cytoscape" class="cytoscape" style="width: 100%; height: 80vh;" id="cytopane"></div>
</v-card>
</v-flex>
</v-layout>
<v-menu v-model="contextMenuOpen" :position-x="x" :position-y="y" absolute offset-y>
<v-list>
<v-list-tile @click="doSomething()">
<v-list-tile-title>Do Somethin</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="doSomethingElse()">
<v-list-tile-title>Do Someting</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</v-container>
</template>
and the js part:
. . .
data: function () {
return {
contextMenuOpen: false,
style: [
{
selector: 'node',
style: {
. . .
}
}, {
selector: 'edge',
style: {
. . .
}
}
],
layout: {
name: 'cose-bilkent'
}
}
},
methods: {
showContextMenu: function (x, y) {
let vs = this
this.contextMenuOpen = false
this.x = x
this.y = y
this.$nextTick(() => {
this.contextMenuOpen = true
})
},
renderView: function (data) {
let vs = this
cytoscape.use(coseBilkent)
let cy = cytoscape({
container: document.getElementById(this.$refs['cytoscape'].id),
elements: data,
style: this.style,
layout: this.layout
})
cy.on('click', 'node', function (evt) {
vs.showContextMenu(evt.originalEvent.clientX, evt.originalEvent.clientY)
})
},
},
mounted() {
. . .
this.renderView()
}
By clicking the button in the toolbar which I put in for testing the context menu would appear. What I find strange is that if the boolean value 'contextMenuOpen' is bound to the v-model of the menu and will be set to true from the on-click handler the value will be set back to false imediately. If I remove the variable from the v-model binding in the v-menu the value will stay true.
Is this a threading issue? What did I do wrong?
UPDATE: I have prepared a js-fiddle that reproduces the problem I have: https://jsfiddle.net/gofrm76/0tkjp3rs/63/
UPDATE2: By creating a watch on contextMenuOpen and setting a breakpoint inside this watch I was able to track the source of the problem down at least a little bit using the stack trace. In fact, the menu appears for a millisecond and closes right away because of a click-outside handler executed in the menu. This would normally happen when the context menu appears and I click a second time somewhere else on the screen to close it again. In the case of the cytoscape on-click event, I apparently miss some kind of event propagation stop because the one click on the node leads to the opening of the menu and the immediate trigger of the click-outside handler.
UPDATE3: I found a config option on the vuetify v-menu that disables the ability to close the context menu by clicking somewhere outside of it. By binding another bool variable to 'close-on-click' that is initially false and will be set to true after a short delay I circumvent the handling of the second event mentioned above and the menu stays open. After the delay, the close-on-click will be set back to the default 'true' and the user is able to close the menu by clicking outside of it.
So for me, this is a solution I can work with for now. It showed also that the assumption from update 2 about the two events is correct and it also shows that the original post is misleading/incorrect: v-menu works as expected but the actual problem is that there are two events being emitted from the "third party lib" / cytoscape.
That leaves me with the question: How can I prevent the second event?