How to position the VuetifyJS popover component? - javascript

I'm using VueJS with the VuetifyJS material design components. How to position the Vuetify popover component below the MORE button? (Currently it's positioned on the upper left, I guess it's the fall back x=0, y=0.)
Button:
<button #click.prevent="openPopover">MORE</button>
Popover Vuetify template:
<template>
<div class="text-xs-center">
<v-menu
offset-x
:close-on-content-click="false"
:nudge-width="200"
v-model="menu"
>
<v-btn color="indigo" dark slot="activator">Menu as Popover</v-btn>
<v-card>
<v-list>
<v-list-tile-action>
<v-btn
icon
:class="fav ? 'red--text' : ''"
#click="fav = !fav"
>
<v-icon>favorite</v-icon>
</v-btn>
</v-list-tile-action>
</v-list-tile>
</v-list>
</v-menu>
</div>
</template>
JS:
<script>
export default {
data: () => ({
fav: true,
menu: false,
message: false,
hints: true
})
}
</script>

I fixed the problem by putting the popover code in a drop down menu.
There are also a couple of options in the API to position the content of the menu.
Examples and API: https://vuetifyjs.com/en/components/menus

Related

Vuetify issues with toolbar item always active

I'm using the Vuetify toolbar: I've three v-tab (on right) and the title (on left) which correspond to the website home.
The v-tabs states works when I click in their component but if I click in title to go back home the last active v-tabs element remain active. In the picture below I'm actually in the home.
enter image description here
I tried to add optional property but it doesn't work
The current code is:
<script>
import Searchbar from "./Searchbar.vue";
export default {
name: "NavBar",
components: { Searchbar },
data() {
return {
appTitle: "ShowCase",
drawer: false // Falso perchè è chiuso, quando si apre diventa vero
};
}
};
</script>
<style>
</style>
<template>
<v-toolbar height="70" color="#252525" dark>
<v-toolbar-title
class="teal--text text--accent-3"
style="cursor: pointer"
#click="$router.push('/')"
title="hover text">
GameShelf
</v-toolbar-title>
<v-spacer></v-spacer>
<Searchbar/>
<v-spacer></v-spacer>
<v-toolbar-items class="hidden-sm-and-down">
<v-tabs optional v-model="tab" fixed-tabs height="70" color="#252525" hover>
<v-tab optional #click="$router.push('/Tuttiigiochi')"> All Games </v-tab>
<v-tab #click="$router.push('/Sceltidallaredazione')"> RetroGaming </v-tab>
<v-tab #click="$router.push('/Aboutus')"> About us</v-tab>
</v-tabs>
</v-toolbar-items>
</v-toolbar>
</template>
How can I make the v-tabs elements inactive when I go back in the home?
you could use a function to redirect user and manually reset tab in your toolbar title element:
#click="redirect"
In your methods:
redirect() {
this.tab = null
this.$router.push('/')"
}
You could also watch the route and set tab to null when route equals '/' ;
watch:{
'$route' (to, from){
if( to === '/') this.tab = null
}
},

Set focus text field inside dialog when dialog opened

I have custom text field and I must focus it functionality when dialog is opened. I tried focus it using vue.js refs:
Code:
<v-app id="app">
<v-row align="center">
<v-col class="text-center" cols="12">
<v-btn color="primary" #click="openDialog()">Open dialog</v-btn>
</v-col>
</v-row>
<v-dialog v-model="dialog">
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Dialog
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="6" class="ml-2">
<v-text-field
ref="name"
placeholder="Enter your name..."
type="text"
solo
flat
outlined
></v-text-field>
<v-btn
color="indigo"
dark
#click = "setFocusName()"
>Set focus</v-btn>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-dialog>
</v-app>
Javascript:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
dialog: false
}
},
methods: {
setFocusName() {
this.$refs.name.focus();
},
openDialog() {
this.dialog = !this.dialog
this.setFocusName()
}
}
});
When I click to open dialog button my text field not focused. Here you can see my full codepen
How I can focus it correctly when dialog is opened?
The problem with your code is that you're trying to access the $ref before it's actually rendered, here's a sandbox with the working code:
https://codepen.io/Djip/pen/ZEYezzm?editors=1011
To resolve the bug i've added a setTimeout to trigger the focus after 0.2 seconds from the open of the dialog. I first tried with $nextTick, but that wasn't enough to do the job - you can try adjusting the timer, to make it as low as possible.
setFocusName() {
this.$refs.name.focus();
},
openDialog() {
this.dialog = !this.dialog
setTimeout(() => {
this.setFocusName()
}, 200)
}
I set the focus logic inside a watcher of the property that toggles the dialog.
watch: {
dialog: function(value) {
if (value) {
setTimeout(() => {
this.$refs.inputrefname.$refs.input.focus();
});
}
}
}

Showing v-menue's selected option in another part of the application. Vuetify

So I have a v-menu with some options. Now I want to display the selected option in another part of my app (same component). I tried to do it using v-model but it doesn't work. What's the best way to do it?
This is the code for the v-menu and where I want to display the selected option:
<v-menu bottom transition="scale-transition" >
<v-btn slot="activator">​
28
</v-btn>
<v-list>
<v-list-tile
v-for="(item, index) in PIFBitems"
:key="index"
v-model="hasan"
#click="boardSwitch('shoPFIB', index)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
.
.
.
<p class="chipPam13"
>{{this.hasan}}</p>
.
.
This is the script code:
data() {
return {
hasan:'',
PIFBitems:[
{title: empty},
{title: PIFB}
]
}
}
Please use hasan rather than this.hasan in your HTML:
<p class="chipPam13">{{hasan}}</p>
Or if v-model doesn't work, you can try to set hasan value at boardSwitch function:
...
methods: {
boardSwitch (firstArg, secondArg, value) {
...
this.hasan = value
},
...
}
Please don't forget to add third argument to your function call in HTML:
<v-list-tile
v-for="(item, index) in PIFBitems"
:key="index"
v-model="hasan"
#click="boardSwitch('shoPFIB', index, item.title)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>

Refactoring vue single file components

As my single file component is getting bigger, I attempted to refactor it a bit. Turns out I have a couple of dialogs that make the .vue file huge (800 lines+). So in order to keep the component clean, I am trying to turn the dialogs into dedicated child components (mydialog). I am using vuetify (familiarity with vuetify is not required).
I have a button in the parent component which enables the dialog. I am sending the dialog prop to the child component which then gets attached to the v-model of the dialog. The problem is, it only works the first time. And that's because as I click the close button, it changes the dialog's value to false and it remains false forever because the child component has lost communication with the parent. Under such circumstances, how can I fix this?
Here is the snippet:
Vue.component('mydialog', {
props:{
dialog: {
type: Boolean,
default: false
}
},
template: `
<div class="text-xs-center">
<v-dialog
v-model="dialog"
width="500"
>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
A Dialog
</v-card-title>
<v-card-text>
Lorem ipsum dolor sit amet,
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
flat
#click="dialog = false"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
`,
data: function() {
return {
// dialog: false,
}
}
});
new Vue({
el: '#app',
data: {
dialog: false
}
});
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.css" />
</head>
<body>
<div id="app">
<v-app id="inspire">
<v-btn color="red lighten-2" dark #click="dialog=true">Click Me</v-btn>
<mydialog :dialog="dialog"></mydialog>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
</body>
</html>
Your component communication was a bit off: basically your dialog did not inform the app component that it was closed. The following two changes enable the upstream communication between modal and app:
In app template:
<mydialog :dialog.sync="dialog"></mydialog>
In mydialog controller:
data: function() {
return {
dialog$: false,
};
},
methods: {
onClose() {
this.dialog$ = false;
this.$emit('update:dialog', this.dialog$);
},
},
watch: {
dialog: {
immediate: true,
handler() {
this.dialog$ = this.dialog;
},
},
}
The first change makes the app component listen to updates on the dialog props of mydialog.
In mydialog I added a data property dialog$ which reflects the dialog props (because props are considered constant and should not be changed). A watcher takes care that downstream updates on dialog update dialog$. The onClose method updates dialog$ when the dialog was closed and emits an update to subscribers (specifically app).
Vue.component('mydialog', {
props:{
dialog: {
type: Boolean,
default: false
}
},
template: `
<div class="text-xs-center">
<v-dialog
v-model="dialog$"
width="500"
>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
A Dialog
</v-card-title>
<v-card-text>
Lorem ipsum dolor sit amet,
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
flat
#click="onClose"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
`,
data: function() {
return {
dialog$: false,
};
},
methods: {
onClose() {
this.dialog$ = false;
this.$emit('update:dialog', this.dialog$);
},
},
watch: {
dialog: {
immediate: true,
handler() {
this.dialog$ = this.dialog;
},
},
}
});
new Vue({
el: '#app',
data: {
dialog: false
},
template: `
<v-app id="inspire">
<v-btn color="red lighten-2" dark #click="dialog=true">Click Me</v-btn>
<mydialog :dialog.sync="dialog"></mydialog>
</v-app>
`,
});
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.css" />
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
</body>
</html>
As #raina77ow has mentioned, you can also solve this kind of issue with an event bus but it's not necessary in this case.

How do I enable text-fields on button click event in Vue.js?

I have a 5 text fields.
1._id,
2.name,
3.display,
4.reference,
5.ref_id
I want to enable only 2nd ,3rd & 4th text fields on a button click. So, I am declaring a variable 'disable' in data section of Vue.js, and calling function enableFields() on button click event. Here's my template code:
<template>
<div>
<!-- Dialog Modal Design -->
<v-dialog v-model="dialog" #keydown.esc="setDialog(false)" width="800px">
<v-card>
<v-card-title
class="grey lighten-4 py-4 title">
<v-icon>fa-envelope-open</v-icon>
Add/Edit a Record
</v-card-title>
<!-- Modal pop up text fields -->
<v-container grid-list-sm class="pa-4">
<v-layout row wrap>
<v-flex xs12 align-center justify-space-between>
<v-layout align-center
v-for="(column, i) in columns"
:key ="i"
v-if="column.field != ''">
<v-text-field
v-bind:value="getEntryFieldData(column)"
:label="column.headerName"
:disabled="disable">
</v-text-field>
<!-- ="(column.headerName == '_id')" -->
</v-layout>
</v-flex>
</v-layout>
</v-container>
<!-- Edit/Update/Cancel Buttons -->
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="secondary" #click="onCancel">
<v-icon>fa-ban</v-icon>
Cancel
</v-btn>
<v-btn color="primary" #click="onCancel">
<v-icon>fa-save</v-icon>
Update
</v-btn>
<v-btn v-if="visible"
color="primary" #click="enableFields">
<v-icon>fa-pencil-alt</v-icon>
Edit
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
And here's my script:
<script>
import {mapGetters} from 'vuex';
export default {
name: 'MasterModal',
props: {
input: Object,
addBtnClick: Boolean
},
data () {
return {
isReadOnly: false,
dialog: false,
valid: false,
visible: true,
disable: true
};
},
computed: {
...mapGetters('masterData', {
entryState: 'entryState',
entryData: 'entryData',
columns: 'columns'
})
},
watch: {
addBtnClick: function (newValue, oldValue) {
this.setDialog(!this.dialog);
}
},
methods: {
setDialog (bValue) {
this.dialog = bValue;
},
// Called when the cancel button is pressed in the form
// Clears and data currently entered in the form and closes the input modal
onCancel () {
this.setDialog(false);
},
// Reading all column values and filling row data into the textbox in the v-for of template
getEntryFieldData (column) {
return this.entryData[column.field];
},
enableFields () {
this.disable = false;
}
}
};
</script>
Basically I am getting confused about assigning property of each text field
as I am generating them dynamically using v-for.
The fastest way to achieve it is this:
<v-text-field
v-bind:value="getEntryFieldData(column)"
:label="column.headerName"
:disabled="disable || i == 0 || i == 4">
</v-text-field>
So adding,
In HTML
:disabled="setDisable(column.field)" works for me.
In Script
setDisable (colName) {
return this.entryState === 'read' || colName.toLowerCase().indexOf('id') !== -1;
}
works for me. Basically I am checking which column.field text has id and disabling it by checking its index.

Categories