Vuetify table will not render when it is placed inside another component - javascript

I made a table component in my project as I have multiple tables that I want to all look the same.
I insert my table onto my page and everything is working fine.
On the table is a dialog which opens correctly but inside that dialog is another one of my table components and this does not render.
It will work if I change the name of the component and have two separate instances but that is not what I am trying to do.
How can I get my table working across all components? Using Vue CLI.
Table component:
<template>
<v-data-table :headers="headers" :items="items" :no-data-text="noDataText" :dark="dark">
<template v-slot:top>
<v-toolbar :dark="dark" flat>
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-divider class="mx-4" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-btn #click="dialog=true" color="success" class="mr-2">
Load Default Frames
<v-icon right>mdi-download</v-icon>
</v-btn>
<v-btn color="primary" class="mr-2">
Create New Frame
<v-icon right>mdi-image-plus</v-icon>
</v-btn>
<Dialog v-model="dialog" />
<!-- <Frame v-model="dialog" :editedFrame="editedFrame" :oldIndex="oldIndex" #close="close" />
<DefaultFrames v-model="defaultFramesDialog" :selectable="true" :items="defaultFrames" />-->
</v-toolbar>
</template>
</v-data-table>
</template>
Dialog component:
<template>
<v-dialog v-model="dialog">
<v-card :dark="dark">
<v-card-title>
{{ name}}
<v-divider class="mx-4" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-btn icon #click="dialog = false">
<!-- <v-icon #click="$emit('close')">mdi-close</v-icon> -->
</v-btn>
</v-card-title>
<Table :is="child_component" :headers="frameHeaders" :items="defaultFrames" />
<v-card-actions>
<v-btn #click="log">Log</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>

Table.vue
<template>
<v-btn #click.stop="emitOpenDialog">Open Dialog</v-btn>
</template>
<script>
export default {
methods: {
emitOpenDialog() {
// I've use vueBus for emiting
this.$bus.emit("open-dialog")
}
}
}
</script>
Dialog.vue
<template>
<v-dialog v-model="dialog"> ... </v-dialog>
</template>
<script>
export default {
data: () => ({
dialog: false
},
created() {
this.$bus.on("open-dialog", this.openDialog)
},
beforeUnmount() {
this.$bus.off("open-dialog")
},
methods: {
openDialog() {
this.dialog = true
}
}
}

Related

Vue.js: How can I put a Login Modal inside a dropdown Menu?

I have the following dropdown menu:
<template>
<v-menu close-on-click transition="slide-y-transition">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" v-bind="attrs" v-on="on">
Menu
</v-btn>
</template>
<v-list>
<v-list-item v-for="(item, index) in menuItemsMisc" :key="index" v-model="item.model">
<v-list-item-title>
<v-btn block color="white" #click="item.fn">{{ item.title }}</v-btn>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<!-- Modal code here -->
</template>
<script>
export default {
name: 'MenuBar',
data: () => ({
loginModal: false,
purchaseModal: false,
menuItemsMisc: [
{ title: 'Login',
model: 'loginModal',
fn: () => { this.loginModal = true}
},
{ title: 'Purchase',
model: 'purchaseModal',
fn: () => { this.purchaseModal = true }
},
]
}),
}
</script>
And I am trying to display this Login Modal When the Login Button is clicked in the dropdown.
<v-dialog v-model="loginModal" persistent max-width="500px">
<v-card class="elevation-12">
<v-toolbar color="primary" dark flat>
<v-toolbar-title>Login form</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text>
<v-form>
<v-text-field name="login" prepend-icon="mdi-account" type="text"></v-text-field>
<v-text-field id="password" name="password" prepend-icon="mdi-lock" type="password">
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary">Login</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
But whenever I click the Login or Purchase Button, I have an error that says:
TypeError: Cannot set property 'loginModal' of undefined
What is the Problem here?
From the Vue docs on v-model:
You can use the v-model directive to create two-way data bindings on form input, textarea, and select elements. It automatically picks the correct way to update the element based on the input type.
The v-model property on your <v-dialog> component is expecting it to be an input of some type.
You should be able to simply change this to a v-if:
<v-dialog v-if="loginModal" persistent max-width="500px">
This will cause the <v-dialog> component to display when your button is clicked.
EDIT: Please also make sure your data property on the Vue instance is declared as a class-style function. If you use a lambda function you will lose the this scope when referring to this.loginModal:
export default {
...
data() {
return {
...
}
}
}

Vuetify : Tooltip doesn't work with custom Component

My tooltip doesn't work with my Custom Component. I wrap a Dialog in a Component and I want to add a tooltip.
My Vue.js version is 2.5.17 and Vuetify 2.1.15
Componant A :
<v-tooltip bottom>
<template v-slot:activator="{ on }" v-slot:item={item}>
<ComponentB v-on="on">
</ComponentB>
</template>
<span>Hello world!</span>
</v-tooltip>
Component B:
<template>
<v-dialog v-model="dialog" persistent max-width="800px">
<template v-slot:activator="{ on }">
<v-icon small v-on="on">
add_comment
</v-icon>
</template>
<v-card>
<v-card-title>
<span class="headline">Title</span>
<v-spacer></v-spacer>
<v-btn icon #click="dialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="pb-0">
Hello world!
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
#click="dialog = false"
>
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
I am beginner in VueJs, so may someone can help me :)
I would personally just move the tooltip into the child component, since it is technically part of the child component anyway. I did the best I could with the example code below, given the limited amount of code you provided in your question. Hopefully this helps!
<!-- Component A (Parent) -->
<template>
<ComponentB :item="item" />
</template>
<!-- Component B (Child) -->
<template>
<v-dialog v-model="dialog" persistent max-width="800px">
<v-tooltip bottom>
<template v-slot:activator="{ on }" v-slot:item="item">
<v-icon small v-on="on">
add_comment
</v-icon>
</template>
<span>Hello world!</span>
</v-tooltip>
<v-card>
<v-card-title>
<span class="headline">Title</span>
<v-spacer></v-spacer>
<v-btn icon #click="dialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="pb-0">
Hello world!
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
#click="dialog = false"
>
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
props: {
item: {
type: Object,
default() {
return {};
}
}
}
};
</script>

Vuetify Dialog Component on a loop for confirmation of delete event

I've a project in which I've a datatable.vue which is looping through a data and showing some data table, have some button like edit, delete. What I want to achieve is in that loop, use a reusable dialog component, which will load and upon confirmation, trigger itemDelete method. the DialogComponent is vuetifiy (v-dialog).
<template v-slot:item.action="{ item }">
<v-btn icon color="blue" :to="{ path: updatePath, query: { id: item.id } }">
<v-icon small>mdi-pencil</v-icon>
</v-btn>
<v-btn icon color="red" #click="$emit('deleteItem', item)">
<v-icon small>mdi-delete</v-icon>
</v-btn>
</template>
this is current code of datatable, and has method deleteItem which deletes the item, I want to modify this and add reusable dialogbox (ill use this dialogbox later in other places), which will have confirmation of delete and triggers itemDelete method here.
on Vueitfy, I got this.
<v-dialog
v-model="dialog"
width="500"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
color="red lighten-2"
dark
v-bind="attrs"
v-on="on"
>
Click Me
</v-btn>
</template>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Confirmation
</v-card-title>
<v-card-text>
Are you sure?
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
#click="dialog = false"
>
Confirm
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
and I made component DialogBox of it, I'm new to Vue. Thanks
There is better way to do this:
write this in your item.action slot:
<template v-slot:item.action="{ item }">
<v-btn icon color="blue" :to="{ path: updatePath, query: { id: item.id } }">
<v-icon small>mdi-pencil</v-icon>
</v-btn>
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on, attrs }">
<v-btn
color="red lighten-2"
dark
icon
v-bind="attrs"
v-on="on"
>
<v-icon small>mdi-delete</v-icon>
</v-btn>
</template>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Confirmation
</v-card-title>
<v-card-text>
Are you sure?
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
#click="deleteItem(item)"
>
Confirm
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
and create the deleteItem method:
method:{
createItem(item){
this.$emit('deleteItem', item);
this.dialog = false;
}
}

Controlling visibility of multiple sibling identical components from the same parent while keeping isolated scope

Using Vue and Vuetify Data Tables I built a table in which each row presents an item of an array of objects.
Each row had a button which triggered a dialog which presented a form in which you could edit each row's data.
Here's the problem with instructions: https://codepen.io/gkatsanos-the-bold/pen/VwZzKeq
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => ({
gateways: [],
dialog: false,
form: {
title: ""
}
}),
mounted() {
this.getGateways().then(data => {
this.gateways = data;
});
},
methods: {
async getGateways() {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts"
);
const data = response.json();
return data;
},
openDialog(item) {
setTimeout(() => {
this.dialog = true;
this.form.title = this.item.title
});
}
}
});
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-content>
<v-container>
<v-data-table :items="gateways">
<template #item="{ item }">
<tr>
<td>{{ item.id }}</td>
<td>{{ item.title }}</td>
<td>
<v-menu>
<template #activator="{ on }">
<v-btn small class="meter-point-options-menu action-column-item" v-on="on">
open menu
</v-btn>
</template>
<v-list>
<v-list-item>
<v-btn color="red lighten-2" dark #click="openDialog()">
Click Me
</v-btn>
<v-dialog v-model="dialog" width="500">
<v-card>
<v-card-title>
ID: {{ item.id }}
</v-card-title>
<v-card-title>
TEXT: {{ item.title }}
</v-card-title>
<v-card-text>
<br> Issues:
<ol>
<li>Every time you close and open a Dialog / Popup, all of the previous ones open together because they're still in the DOM.</li>
<li>Notice that after navigating the pages, some of the ID and texts shown in the modal dialogs are different from the item opened!</li>
<v-form ref=form>
</v-form>
</v-card-text>
<v-card-actions>
<div class="flex-grow-1"></div>
<v-btn color="primary" text #click="dialog = false">
close this
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-list-item>
</v-list>
</v-menu>
</td>
</tr>
</template>
</v-data-table>
</v-container>
</v-content>
</v-app>
</div>
As you see opening one dialog opens all the previous ones.
How should I tackle the issue of controlling the visibility of the v-dialogs in a unique fashion? I am thinking of moving them outside of the loop and having only one v-dialog and not one for every row of the table.

v-for key as a v-model in VueJS not working

I am using Vuetify framework for VueJS and I am trying to recreate the Data table edit dialog but instead of static values, I want the edit dialog to be dynamic (User can specify editable fields).
The problem is that I can't use the key I get from v-for for v-model like this.
<v-dialog v-model="dialog" max-width="500px">
<v-card>
<v-card-title>
<span class="headline">Edit Item</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12 sm6 md4 v-for="(item, key, index) in editable_fields">
{{key}}
<h1>{{editedItem}}</h1>
<v-text-field v-model="editedItem.key" :label="key"></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat #click.native="close">Cancel</v-btn>
<v-btn color="blue darken-1" flat #click.native="save_edit">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
And these are my props and data:
props: {
editable_fields: {
type: Object
default: ()=> {name: '', email: ''}
}
}
data: ->
editedItem = #editable_fields
return {editedItem: editedItem}
So the question is how should I approach to this?

Categories

Resources