Vuetify open dialog with custom logic - vue.js

I want to open a dialog on a button click. But i need logic to be executed before and after this event. How can this be done?
What i have tried:
template
<v-dialog v-model="dialog" width="400">
<template v-slot:activator="{ on }">
<v-btn color="primary" #click="openDialog">Dialog</v-btn>
</template>
<v-btn>lol</v-btn>
</v-dialog>
script
data() {
return { dialog: false };
},
methods: {
openDialog() {
this.dialog = true;
}
}
}
This seems like a bad fix because after all the v-slot on is still there.

You don't really need to use v-slot:activator="{on}" in the first example - <v-dialog> tags can be activated without that (as described in the "Without activator" example here).
However, the recommended way for me personally would be the second example you have provided - the one that uses v-on to trigger the dialog, as it handles opening the dialog without writing an extra function to set one of your data variables.

Related

Access to a slot function inside a child component in VusJS

I'm trying to use tiptap. Actually it works, but what I'm trying to do is to access the "isActive" slot from outside the editor component, and I don't know how to do it.
Here is a codesandbox example: https://codesandbox.io/s/v07xnxo807?file=/src/App.vue
You see the Editor component is called from the App.vue. The buttons in the Editor component are activated depending on the "isActive" slot functions.
What I would like is to access this slot to get for example the value of isActive.bold() from the App.vue, in order to update the model of a "multiple button" you can find on Vuetify: https://vuetifyjs.com/fr-FR/components/button-groups/
Here is for example what I could have:
<editor-menu-bar :editor="editor" v-slot="{ commands, isActive }">
<v-btn-toggle
v-model="toggle_multiple"
dense
background-color="primary"
dark
multiple
class="my-2"
>
<v-btn :color="isActive.bold()?'red':'green'" #click="commands.bold">
<v-icon>mdi-format-bold</v-icon>
</v-btn>
<v-btn #click="commands.italic">
<v-icon>mdi-format-italic</v-icon>
</v-btn>
<v-btn #click="commands.strike">
<v-icon>mdi-format-strikethrough</v-icon>
</v-btn>
<v-btn #click="commands.underline">
<v-icon>mdi-format-underline</v-icon>
</v-btn>
<v-btn #click="commands.blockquote">
<v-icon>mdi-format-quote-open</v-icon>
</v-btn>
</v-btn-toggle>
</editor-menu-bar>
And the toggle_multiple would be computed depending on the different "isActive" function values.
I already tried:
computed: {
toggle_multiple: function () {
let t = []
if (editor) {console.log("Bold: "+editor.isActive.bold())}
return t
}
},
But I receive this error: error 'editor' is not defined
I'm open to any suggestion.
Thanks in advance.
Property isActive is stored in the tiptap instance (in your case it's this.editor):
In HTML:
<div>{{editor.isActive.bold()}}</div>
In JS:
<div>{{toggle_multiple}}</div>
computed: {
toggle_multiple () {
// Keep in mind, other properties like ".isActive.heading()" will be undefined
// until you import the extension for it.
// So the function "heading" below exists only if you're using that extension
// console.log(this.editor.isActive.heading({ level: 2 })
return this.editor.isActive.bold()
}
}

console.log not working when using #submit directive in vuetify

When using the #submit directive in Vuetify, console.log is not working in my code. But when I only use #click and then call my function it works. Any idea how to make that work?
This code works:
<v-btn color="primary" text #click="submit">I accept</v-btn>
HTML in template
<v-btn color="primary" text #submit="submit">I accept</v-btn>
Function being called
methods: {
submit() {
console.log.$refs
// Form validation check
if (!this.$refs.invoiceform.validate()) {
console.log("Not good");
} else {
console.log("Data ok");
}
},
Your problem I believe is that v-btn does not have a #submit event so you need to put that on the v-form element if you are using it. Make sure your button is inside the form element and it is of the type submit. Use prevent on the form submit event to prevent it from causing the browser to try to post your form.
<v-form #submit.prevent="submit">
...//some inputs
<v-btn type="submit">I accept</v-btn>
</v-form>

Vue Vuetify open dialog component onclick

Edit: I figured out why the dialog isnt opening. The child component is not receiving the openComment event. I checked in the root component, and that is receiving the event correctly. Any suggestions on why sibling components are not receiving the events? It could also be because I am not using the component in anything, but because it is the modal itself, I dont really want to import it to any other vue file.
I am trying to figure out a way to open a modal dialog from my toolbar. The toolbar lives in one component file, and the dialog lives in another component file. I am trying to acheive this using events, but i cant seem to get it to trigger. What i have tried is sending a custom even which is supposed to see the set the vmodel for the dialog to true. I am using Vuetify to create the dialogs.
My dialog component file is:
<template>
<v-dialog persistent
v-model="commentDialog"
transition="dialog-transition">
<v-card>
<v-card-title primary-title>
Add a comment
</v-card-title>
<v-card-text>
<v-flex xs12 sm6 md4>
<v-text-field label="Legal first name*" required></v-text-field>
</v-flex>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script>
import { bus } from '../main'
export default {
name: 'CommentModal',
data() {
return {
commentDialog: false
}
},
created() {
bus.$on('openComment', function () {
this.commentDialog = true
})
},
}
</script>
<style>
</style>
The toolbar component includes the following:
<template>
<v-btn fab small
#click="commentThis($event)"
<v-icon>fas fa-comment</v-icon>
</v-btn>
</template>
<script>
commentThis: function (e) {
bus.$emit('openComment')
}
</script>
Bonus and follow up question to this question would be how can i see the event bus on the vue chrome debugger?
The problem with function context
created() {
const self = this
bus.$on('openComment', function () {
self.commentDialog = true
})
},
or
bus.$on('openComment', () => (this.commentDialog = true))
Bonus and follow up question to this question would be how can i see the event bus on the vue chrome debugger?
import Vue from 'vue'
const bus = new Vue()
window.__myBus = bus
export { bus }
I solved the issue. It seems like i had to call the component somewhere in my toolbar component vue file. So i called it as ` and that enables the CommentModal component to react the the sent events. If the component is not called anywhere in the sibling components, then it does not react to any of the events.
But I would love to hear if there is a better solution to this. It feels a bit hacky to me.

Vue Change icon to click on the button

how can I change the icon when I click on the button in vue.
Here is a portion of the code:
<v-btn flat icon color="white">
<v-icon>star_border</v-icon>
</v-btn>
Thanks
<v-btn #click="show = !show" icon>
<v-icon>{{ !show ? 'mdi-eye' : 'mdi-close' }}</v-icon>
</v-btn>
add to component
{
data(){
return {
show:false
}
}
}
Hi Enzo and congrats on starting your VueJS project.
I would recommend you looking at VueJS documentation about Data and Methods, to give you some start. https://v2.vuejs.org/v2/guide/instance.html#Data-and-Methods
In short Data is where you keep your reactive properties and Methods store your functionality.
Right now the name of the icon is hard-coded. What you want to do is to make it reactive. So to change the icon;.
You need to bind the name of the icon to a property in your data.
Define a method that changes the value of that property.
Make an on-click event to invoke a function.
Something like this:
new Vue({
el: '#app',
data() {
return {
myIcon: 'star_border'
}
},
methods: {
changeIcon() {
this.myIcon = 'home'
}
}
})
Here I've defined a property called myIcon, which is 'star-border' at first. I've also created a method that gets invoked on the click-event of this button. This method changes the value of the myIcon property to 'home'.
You can see a working demo here: https://codepen.io/bergur/pen/MLMxzY

Vue / vuetify focus input after modal is dismissed

On a page I have a Vuetify v-form/v-text-field. Users can type a query in to this form and press Enter to update the page.
Sometimes the query is erroneous and a v-dialog modal pops up to explain the error. It's a complex error and can't just be packed in the rules attribute of the v-text-field.
The problem: when the modal is dismissed, the v-text-field is no longer focused and requires a click before it can be used again. This interrupts the user and requires a shift from keyboard to mouse and back.
What is Vue best practice for re-focusing on the input that triggered the modal?
I can think of one idea it doesn't feel Vue-ish: put a ref on the v-text-field and watch the dialog data property. If dialog becomes false, call this.$refs.input.focus(). However, this seems like the old-fashioned, imperative (not reactive) way to do it. For example:
<template>
<v-form v-model='valid' #submit.prevent='submit'>
<v-text-field
placeholder="Search..."
v-model="query"
:rules="[foo]"
ref='input'
autofocus
></v-text-field>
<v-dialog
v-model="dialog"
#keydown.esc='dialog = false'
>
{{ someErrorMessage }}
</v-dialog>
</v-form>
</template>
// Vue instance
export default {
data: function() {
return {
dialog: false,
query: "",
valid: false
}
},
...
watch: {
// Focus on query after dismissing an error
dialog(newState) {
if (!newState) {
this.$refs.input.focus();
}
}
},
methods: {
foo(value) {
// ... validate value
},
submit(e) {
if (!this.valid) {
this.dialog = true;
return;
}
}
}
}
In the dialog element, I'd probably call a method instead of directly changing dialog to false. Then in that method, I'd add focus to the textarea with some plain old javascript.