Im trying to show the dialog when I click the Dashboard link.
The problem is I can't change the dialog value to true since its inside the data method. What's the correct way to do it?
export default {
data: () => ({
drawer: true,
dialog: false
}),
props: {
source: String
},
methods: {
me: () => {
alert('me')
},
showDialog: () => {
this.dialog = true
}
},
computed: {
months: () => (
this.months = ['na', 'asd', 'asd']
)
}
}
Here is the layout in jsfiddle https://jsfiddle.net/vfztk8ve/
I noticed following code in your layout.
<v-btn color="blue darken-1" flat #click.native="dialog = false">Close</v-btn>
<v-btn color="blue darken-1" flat #click.native="dialog = false">Save</v-btn>
I'd like to say you are in the perfect way to close the dialog and set the component's dialog value as false.
Actually data method performs like a variable rather than a method in component, because we won't share a value in the component across all component instance. Following are official document.
When defining a component, data must be declared as a function that returns the initial data object, because there will be many instances created using the same definition. If we use a plain object for data, that same object will be shared by reference across all instances created! By providing a data function, every time a new instance is created we can call it to return a fresh copy of the initial data.
Related
I have a bit of a quantum problem happening. I have some code (below) that is not displaying the value of the data model. So I put a console.log in to see what's going on and then it works... none of the other code changes, but by looking at it, it exists. Then if I refresh the page, it's gone again
[Update] It's not the console.log itself (whew - that would be wierd). It's the state when I change the file vs when i do a fresh browser load. What's different there that I should be looking at? I'm new to VueJS, and I'm really more of a python / backend dev anyway, so sorry if this is basic stuff.
The template code in child component
<v-text-field v-else
#change="updateValue(field.name, $event)"
persistent-placeholder
:model-value="(item as any)[field.name]"
:label="field.title || field.name"
></v-text-field>
item is passed in as a Model and converted as follows
props: {
input: {
type: Object || null,
default: null
},
},
data() {
return {
item: {...this.input},
}
},
which comes from the parent
<ModelComponentVue
:input="item"
/>
which gets the data in created()
DataStore.query(User).then((items:Array<User>) => {
if (items.length > 0) {
this.item = items[0] // I suspect this could be not responding to reactivity in Vue3 ???
}
})
Parts of your code only use initialData contrary to what you might think. Pay attention to the code below.
data() {
return {
item: {...this.input},
}
},
In the above code, you will only have the initial value of the input and you will lose the other values.
The easiest way to use props is to use them directly.
However, for more complex concepts, you can use computed or toRef, etc.
Try the code below
<v-text-field v-else
#change="updateValue(field.name, $event)"
persistent-placeholder
:model-value="input[field.name]"
:label="field.title || field.name"
></v-text-field>
props: {
input: {
type: Object ,
default: () => {}
},
},
I have a Vuetify combobox that on save does an api call to store the selected or entered value. However, when updating this value, if the save button is clicked directly without deselecting the combobox, the previously stored value is stored again, instead of the new value. Only when I manually unselect the box or press enter does the correct value store. I have looked around and found certain fixes that have worked for others, such as .blur() and .$nextTick, but they haven't seemed to work for me (I could be implementing them incorrectly). Here's what I have:
Combobox:
<v-combobox
:items="suggestions"
v-model="editedItem.field_label"
label="Label"
outlined
dense
ref = "comboBox"
></v-combobox>
Save button:
<v-btn color="blue darken-1" text #click="save"> Save</v-btn>
Save function:
save() {
this.$refs.comboBox.$emit("blur")
this.$nextTick(() => {
const device_field = {
...this.editedItem,
};
device_field_api
.updateDeviceField(device_field, this.device_id)
.then((r) => {
//Various logging items
);
})
.finally(this.initialize())
.catch((e) => {
//Error catching
);
});
});
}
Change
this.$refs.comboBox.$emit("blur")
to this:
this.$refs.comboBox.blur().
Codepen example
Result:
I made a component called dialog, and I want to make it plugin and register it as a global function.
However, I don't know how to access the component from plugin and call the component's method.
import Vue from 'vue'
import AlertDialog from '#/components/AlertDialog'
const methods = {
openDialog: (
maxWidth,
title,
message
) =>
AlertDialog.openDialog(
maxWidth,
title,
message
),
closeDialog: () => AlertDialog.closeDialog()
}
Vue.prototype.openDialog = methods.openDialog
Vue.prototype.closeDialog = methods.closeDialog
This is a dialog_plugin.js.
But it doesn't work.
edit
::
<template>
<v-dialog
v-if="isShow"
v-model="isShow"
:max-width="maxWidth ? maxWidth : 290"
>
<v-card>
...
</v-card>
</v-dialog>
</template>
<script>
export default {
data() {
return {
isShow: false,
maxWidth: null,
title: null
}
},
methods: {
openDialog(
maxWidth,
title
) {
this.isShow = true
...
},
closeDialog() {
this.isShow = false
}
}
}
</script>
This is AlertDialog.vue
A component's methods are only intended to be called from within the component itself. Trying to expose them to be called by outside code is really going against the way Vue is designed to work.
If you want to affect the state of a component from outside of itself, there are a couple of ways:
Props - Rather than isShow being a piece of the AlertDialog's state, you would pass this value in as a prop. That way the parent component can change the value to show/hide the alert as needed.
Vuex - If you needed to have a single instance of a component in your app (e.g. for a toast display), having it receive its state from a Vuex store would make it easy to display messages from any part of your app.
An Event Bus - For a simpler app where you don't want to bring in Vuex, you can always use an instance of Vue as an event bus, to control your component by emitting events from anywhere else in your app. Your component can then listen for these events and show/hide as needed.
I'm passing down an array of image urls as props to my Konva component, creating a image object for each url, storing that object in a data object (using Vue's $set method to keep the object literal reactive), then using v-for to create a v-image for each image object in my data object. This seems to be working fine, however I'm running into a problem where if I try to remove one of the images, 2 images will be removed. This only happens if the image that I try to remove is not the topmost image. In the console, I'm getting the warning Konva warning: Node has no parent. zIndex parameter is ignored.. My hunch is that this is a result of konva's destroy method clashing with vue's $delete method on a data object used in a v-for. I've been battling with this for hours, and would appreciate any help I can get. Relevant code is below. Thanks!
Parent
<template>
<editor ref="editor" :image-props.sync="images"/>
<button #click="remove">remove</button>
</template>
export default {
components: {
Editor,
},
data() {
return {
images: [url1, url2, etc...],
};
},
methods: {
remove() {
this.$refs.editor.removeSelectedImage();
},
}
child
<template>
<div>
<v-stage>
<v-layer>
<v-group>
<v-image v-for="image in Object.values(images)"
:key="image.id" :config="image"/>
</v-group>
</v-layer>
</v-stage>
</div>
</template>
export default {
props: {
imageProps: Array,
},
data() {
return {
images: {},
selectedNode: null //this gets updated on click
},
watch: {
imageProps() {
this.registerImages();
},
mounted() {
this.registerImages();
},
methods: {
registerImages() {
this.imageProps.forEach(url => {
if (!this.images[url]) {
let img = new Image();
img.src = url;
img.onload = () => {
this.$set(this.images, url, {
image: img,
draggable: true,
name: url,
x: 0,
y: 0,
});
}
}
});
},
removeSelectedLayer() {
let newImageProps = this.imageProps.filter(url => url !== this.selectedImageName);
this.$emit('update:image-props', newImageProps);
this.selectedNode.destroy();
this.$delete(this.images, this.selectedImageName);
this.stageArea.draw();
},
If I inspect the component in Vue devtools, the images object looks correct as well as imageProps, (even the Vue DOM tree looks right with the correct amount of v-images) however the canvas shows 1 less image than it should. Again, this only happens if I remove a image that wasn't initially on top. It seems to function fine if I remove the top-most image.
When you are developing an app with vue-konva it is better not to touch Konva nodes manually (there only rare cases when you need it, like updating Konva.Transformer).
You don't need to call node.destroy() manually. Just an item for your data.
From your demo, I see you are not using key attribute (you are using image.id for that, but it is undefined). It is very important to use keys in such case.
Updated demo: https://codesandbox.io/s/30qpxpx38q
There is a v-select component and on change I am firing up fillData(selected) where selected is the v-model. And I need to update the label in datacollection.datasets.label on change. How do I do that ?
<script>
import BarChart from './BarChart.js'
import { mapGetters, mapActions } from "vuex";
export default {
name : "TestLegPerformance",
components: {
BarChart
},
data: () => ({
datacollection : {
labels: ['Week-1','Week-2','Week-3'],
datasets: [
{
label: '',
backgroundColor: '#C58917',
data: [40, 50, 20]
}
]
},
selected: []
}),
computed: {
...mapGetters({
planNames: "planNames"
})
},
mounted () {
this.getAllPlanNamesAction();
},
methods: {
...mapActions(["getAllPlanNamesAction"]),
fillData(selected){
console.log(selected)
},
}
}
</script>
Inside methods, you can reference to data properties using this.
In your case, you can use this.datacollection.datasets.label and assign to it:
methods: {
// ...
fillData(selected){
this.datacollection.datasets[0].label = selected;
},
}
Of course, this assuming that selected is the string you want to assign to the label.
Note: the this will only work when you declare the methods using methodName() {} (as you are) or methodName: function (){.... So don't use arrow functions when declaring vue methods, they will mess up your this.
Bind to events using # (v-on) not : v-bind)
Your template:
<v-select label="Select a Plan" :items="planNames" v-model="selected" single-line max-height="auto" :change="fillData(selected)" required >
To listen to the change event, don't use:
:change="fillData(selected)"
use
#change="fillData"
Don't send an argument (it will mess things up). v-select will send you one already.
Notice the replacement of : with #.
The first, : is an alias to v-bind. So :change="xyz" is the same as v-bind:change="xyz".
The second, # is an alias to v-on. So #change="xyz" is the same as v-on:change="xyz". which is what you want.
See demo JSFiddle here.
Updating label of vue-chartjs's BarChart automatically
Even though you are
using the reactiveProp mixin; and
changing the label
The chart is not reflecting the changes (the label does not change) automatically.
I noticed this happens because the chart only reacts to whole datacollection changes, not to inner properties (like label).
So the solution is to:
"clone" datacollection
update the label of the clone
assign the clone to this.datacollection
And the chart will react (the label change will be reflected).
So, change your fillData method to the following:
fillData(selected){
let collectionClone = Object.assign({}, this.datacollection);
collectionClone.datasets[0].label = selected;
this.datacollection = collectionClone;
},
Check here a working DEMO CODESANDBOX of this solution (see the changeLabelAndReassign() method of BarChart.vue).