Vuetify give props activator in many components such as v-menu or v-dialog,but there are no more details about how to creat a node to work properly.
The document describe like this
Designate a custom activator when the activator slot is not used. String can be any valid querySelector and Object can be any valid Node.
But i use querySelector to pick a simple element and it didn't work,any additional property should i add?
As far as I know, there is no additional props. The activator prop accept 3 different types.
With Selector:
<v-app>
<v-btn class="my-btn">Dropdown</v-btn>
<v-menu activator=".my-btn">
<v-list>
...
</v-list>
</v-menu>
</v-app>
Example
With Component:
<v-app>
<v-btn ref="myBtn">Dropdown</v-btn>
<v-menu :activator="myBtnRef">
<v-list>
...
</v-list>
</v-menu>
</v-app>
new Vue({
data: () => ({
myBtnRef: null,
...
}),
mounted() {
this.myBtnRef = this.$refs.myBtn
}
}).$mount('#app')
Example
With HTMLElement:
<v-app>
<v-btn>Dropdown</v-btn>
<v-menu :activator="myBtn">
<v-list>
...
</v-list>
</v-menu>
</v-app>
new Vue({
data: () => ({
myBtn: null,
...
}),
mounted() {
let button = document.createElement('button')
button.textContent = 'Dropdown'
document.body.insertBefore(button, document.body.firstChild)
this.myBtn = button
}
}).$mount('#app')
Example
Related
I'm having trouble using jquery append with vuetify. I can't write any vuetify code in my javascript. It wouldn't show me the vuetify code, but it should work. I think it has something to do with vuetify having to be restarted when you want to insert a new vuetify code.
new Vue({
el: '#app',
vuetify: new Vuetify(),
methods: {
createList() {
if (this.$refs.form.validate()) {
$('#lists').append(`
<v-card width="374" class="mx-10 my-12" elevation="5">
<v-system-bar color="${this.color.hexa}" dark><b>${this.name}</b></v-system-bar>
<v-form ref="form" lazy-validation>
<v-card-actions>
<v-text-field v-model="name" ref="name" class="mx-5" :rules="jobsTitleRules" label="Title" required></v-text-field>
<v-btn color="success" #click="addTitle">Add</v-btn>
</v-card-actions>
<ul style="padding: 0px;" id="jobs"></ul>
</v-form>
</v-card>`);
}
},
},
})
Searched everywhere and really can't find a solution. Anyone who can help?
As I mentioned in comments, jQuery append function was designed to add native HTML, native JS, or jQuery objects.
It is not possible to use it with Vue/Vuetify because you are trying to show virtual template components which are not native.
In your case you can use a list of Vue dynamic components.
First of all, you need to create your dynamic component (I simplified your template a little):
const externalForm = Vue.component('external-form', {
props: {
name: String,
color: String,
},
data() {
return {
internalName: this.name,
}
},
methods: {
addTitle() {
this.$emit("emit-title", this.internalName)
}
},
template: `
<v-card width="374" class="mx-10 my-12" elevation="5">
<v-system-bar :color="color" dark><b>{{name}}</b></v-system-bar>
<v-card-actions>
<v-text-field v-model="internalName" class="mx-5" label="Title"></v-text-field>
<v-btn color="success" #click="addTitle">Add</v-btn>
</v-card-actions>
</v-card>`,
});
When you need to pass some data to component, you should use props. For internal data you can use data section. And if you need to return some data, you can emit some event.
Now let's see how we can use it in your main template. Assume you already have some list of <v-list-item> components. You need to add some items into the tail of the list. This way, by example:
<v-btn #click="addItem" color="primary">Click here to add item</v-btn>
...
<v-list-item v-for="(item, key) in items" :key="key">
<component :is="item.component" v-bind="{...item.props}" #emit-title="pushToList"/>
</v-list-item>
And finally you need to define your main component:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
items: [],
titles: []
}
},
methods: {
pushToList(val) {
this.titles.push(val)
},
addItem() {
this.items.push({ component: 'external-form', props: {
name: 'Some name',
color: '#' + Math.floor(Math.random() * 16777215).toString(16) //Just a random color HEX
}})
}
}
})
I hope now you can apply this method to your business logic.
CodePen playground is available here.
I have a vue app where I send one array from one component to another. which works. But now I want to visually show this. What I mean is like this:
Array 1 has the field date and time inside it which is copied to the parent Array 2 I can log this but if I want to show a specific value for example date itself it does not show anything and gives the error the property can not be read. I tried looping through the parent array but it did not work causing in the can not read property error.
Could someone give me a pointer on how to fix this.
Childcomponent method and array to be copied the method fills the array here with data:
data: () => ({
selectedTime: [],
dates: [{date : new Date().toISOString().substr(0,10), time: []}],
}),
methods:{
addTimeFields(){
this.selectedTime.push({
startTime:"",
endTime: "",
})
this.dates[0].time.push(
this.selectedTime
)
},
Parent component which should get the array here I am trying to push the array from child to parent array which works (save method) but when I try to loop though it gives me an error:
<v-card-text v-for="(i,index) in finalDate">
<v-btn >
{{i.finalDate}}
</v-btn>
</v-card-text>
<v-divider class="mx-4"></v-divider>
<v-card-actions>
<v-spacer />
<v-col>
<vs-button>Generate Meeting Link</vs-button>
</v-col>
{{finalDate}}
</v-card-actions>
</v-card>
</template>
<script>
import MeetingsTableComponent from "#/components/MeetingsTableComponent";
import DatePickerComponent from "#/components/DatePickerComponent";
export default {
name: "NextMeetingCardComponent",
components: { DatePickerComponent },
data: () => ({
dialog: false,
finalDate: [],
menu: false,
modal: false,
menu2: false
}),
methods:{
save() {
this.finalDate.push(
this.$refs.datepicker.dates
)
}
Error:
[Vue warn]: Property or method "date" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
---> <NextMeetingCardComponent>
<DashboardComponent> at src/views/DashboardComponent.vue
<VMain>
<VApp>
<App> at src/App.vue
<Root>
You have a random {{ date }} in your component:
<v-card-text v-for="(i,index) in finalDate">
<v-btn >
{{i.date}}
</v-btn>
</v-card-text>
<v-divider class="mx-4"></v-divider>
<v-card-actions>
<v-spacer />
<v-col>
<vs-button>Generate Meeting Link</vs-button>
</v-col>
{{date}} <---- HERE
</v-card-actions>
</v-card>
</template>
Could this be the issue?
I am wondering how I take an existing (initial) v-data-table component whose :headers and :items props are populated, and then completely re-render the component with new data and new column headers? Is there a special update or destroy native Vue or Vuetify way to do this?
I want my UX to be: See initial table that is created on mount, choose new columns, click update, queue loader icon, table is re-rendered with new items and new headers.
Thanks in advance.
VDataTable is driven by the data you feed to it through headers & items. If the sources change, the table changes. So, don't do anything else, just update the sources (in a reactive way) & your table is going to update according the new set of data fed to it.
new Vue({
el: '#app',
vuetify: new Vuetify(),
computed: {
headers() {
return this.items.length ? Object.keys(this.items[0]).map(key => ({
value: key,
text: key
})) : []
}
},
data() {
return {
items: []
}
},
methods: {
async fetchData(type) {
const response = await fetch(`https://jsonplaceholder.typicode.com/${type}`)
this.items = await response.json()
console.log(this.items)
},
}
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-main>
<v-container>
<v-row>
<v-col>
<v-btn-toggle>
<v-btn #click="fetchData('users')">
FETCH USERS
</v-btn>
<v-btn #click="fetchData('posts')">
FETCH POSTS
</v-btn>
</v-btn-toggle>
</v-col>
</v-row>
<v-row>
<v-col>
<v-data-table :headers="headers" :items="items" />
</v-col>
</v-row>
</v-container>
</v-main>
</v-app>
</div>
In Vue/Vuetify, how do we hide/show dialogs from parent? I'm trying to use v-model and here is a simplified version of my setup:
Parent component (just a button that triggers the child component to show)
<template>
<div>
<v-btn class="ma-2" outlined fab color="red" small #click.stop="editItem()">
<v-icon size="16">mdi-close-circle</v-icon>
</v-btn>
<user-dialog v-model="dialog" :eitem="editedItem" class="elevation-2" />
</div>
</template>
<script>
import UserDialog from "./UserDialog.vue";
export default {
components:{
UserDialog
},
data() {
return {
counter: 0,
dialog: false,
editedItem: {},
}
},
methods: {
editItem: function() {
this.counter++;
this.editedItem = Object.assign({}, {
title: 'some title' + this.counter,
details: 'some details for this item'
});
this.dialog = true;
},
},
}
</script>
Child component (basically a dialog box)
<template>
<v-dialog v-model="value" max-width="500px">
<v-card>
<v-card-title>
<span class="headline">A Dialog</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12>
<v-text-field v-model="eitem.title" label="Title"></v-text-field>
</v-flex>
<v-flex xs12>
<v-text-field v-model="eitem.details" label="Details"></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" text #click.stop="save">Save</v-btn>
<v-btn color="blue darken-1" text #click.stop="close">Cancel</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
props: {
value: Boolean,
eitem: Object,
},
data() {
return {
editedItem: this.eitem,
}
},
methods: {
save() {
//perform save
this.$emit('input', false);
},
close() {
this.$emit('input', false);
},
},
}
</script>
This setup works, but give the following warning:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
But if act upon this advice and declare a data item in the child component and set v-model of the v-dialog to this data item, the dialog stops showing up upon click.
I perhaps understand why it does that, but cannot figure out a proper way of fixing this that doesn't show warnings. Can anyone help me with this?
Since Vue throws a warning when you mutate props, you should not use v-model with props. To handle this use the following pattern:
computed: {
propModel: {
get () { return this.value },
set (value) { this.$emit('input', value) },
},
},
Define computed property with getter, that returns props.value, and setter that emits input event (that will be successfully handled in parent, since you use v-model)
Don't forget to chage your template:
<v-dialog v-model="propModel" max-width="500px">
This works for me and do not need to create a computed data.
<v-dialog
width="600px"
:value="value"
#input="$emit('input', $event)"
>
</v-dialog>
I do not understand what i am doing wrong. I'm using Vuetify framework with nuxt.js on top of vue.js.
I wish that the navigation drawer's initial state to be open on the index page but close on the others. I can manage to have the desired result when i first load the page (if it's the index page the drawer is shown otherwise it's hidden), but when i change the page using the link in the drawer (nuxt js is using vue router in the background) the drawer preserves it's state.
I've made a quick middleware containing this:
export default ({store, route}) => {
const mitem = store.state.menu.filter(item =>
item.to.indexOf(route.name) >= 0
)[0]
const title = mitem ? mitem.title : 'Home'
store.commit('setPageTitle', title)
}
here's the store were are the state and mutations (the menu json file contains the entries with the following keys: { title, icon, to })
import menu from '~json/menu.json'
export const state = () => ({
menu,
drawer: true,
pageTitle: undefined
})
export const mutations = {
toggleDrawer: state => {
state.drawer = !state.drawer
},
setPageTitle: (state, title) => {
state.pageTitle = title
state.drawer = title === 'Home'
console.log(state.drawer)
}
}
And here's the layout
<template>
<v-app>
<v-navigation-drawer
persistent
v-model="drawer"
>
<v-list>
<v-list-tile
router
v-for="(item, i) in menu"
:key="i"
:to="item.to"
>
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar fixed>
<v-toolbar-side-icon #click.native.stop="toggleDrawer" />
<v-toolbar-title>{{ pageTitle }}</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<main>
<v-container fluid>
<nuxt />
</v-container>
</main>
</v-app>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
methods: {
...mapMutations([ 'toggleDrawer' ])
},
computed: {
...mapState([ 'menu', 'drawer', 'pageTitle' ])
}
}
</script>
The console.log shows me that the state get updated, but as the state.drawer changes the component is not updated and the drawer remains present.
Any idea on what i'm doing wrong/how to tackle that issue?
Thanks in advance
Seb
The v-navigation-drawer component by default watches for changes in $route. You can disable this functionality by adding the prop disable-route-watcher. Making this change will allow you to minutely control the state of the component.