I have a vue component like below.
And I want to use watch for a specific keyword not everything.
So I made a computed function to focus it.
The code below works very well.
var vm = new Vue({
el: '#app',
computed: {
foo() {
return this.item.foo;
}
},
watch: {
foo() {
console.log('Foo Changed!');
}
},
data: {
item: {
foo: 'foo'
}
}
})
And I applied to my example. In this case, it doesn't work well. So I guess it should be used by 'deep: true' inside of 'changedOptions' of watch. But I don't know how can I use 'deep' inside of a function.Could you recommend some solutions?
data(){
return {
deliveryOptions: {
weight: 3,
options: { express: false, shuttle: false, bike: true, walk: false },
},
computed: {changedOptions() {
return this.deliveryOptions.options;
}
},
watch: {
changedOptions(){
console.log('changed')
}
}
Computed only runs when you use computed value somewhere.
you can either use it in the template part or in the script.
lets us use it in mounted like below
mounted () {
console.log(this.changedOptions)
// this will call the computed to return the value.
}
if the watcher still doesn't run then you can try immediate: true in watcher like below
watch: {
changedOptions: {
immediate: true,
handler () {
console.log('changed')
}
}
}
Related
I have these computed properties in a component:
computed: {
messageText: {
get() {
return this.getMessageProp('messageText') // Maps to a vuex getter
},
set(value) {
this.setMessageProp(['messageText', value]) // Maps to a vuex mutation
}
},
location: {
get() {
return this.getMessageProp('location')
},
set(value) {
this.setMessageProp(['location', value])
}
}
}
This works on browser refresh. As you can see it's a bit repetitive (There are a few more in other components).
I tried to create them dynamically like this:
data() {
return {
stepProps: {
messageText: {},
location: {},
}
}
},
created() {
Object.keys(this.stepProps).forEach((key) => {
if (!this.$options.computed[key]) {
this.$options.computed[key] = {
get() {
return this.getMessageProp(key)
},
set(value) {
this.setMessageProp([key, value])
}
}
}
})
}
But it does not work on browser refresh. I get the error:
Property or method "messageText" is not defined on the instance but referenced during render....
It works when switching components (I am using Vue router)
How can I get this, or something similar, to work? Ultimately I wanted to put it into a mixin to reuse in other components.
I have a method "aggiornaQuantity" in this component that i would use in my vue. How can i do?
Obviously I did various tests without any success
Vue.component('todo-item', {
props: ['todo'],
template: '...',
methods:
{
aggiornaQuantity: function()
{
return this.todo.quantity = this.value ;
}
}
var app7 = new Vue
(
{
el: '#app-7',
data:
{
message: '${Message}',
risultato: true,
groceryList: [],
product: '',
selected: '',
},
methods:
{
.....
}
Edit: I'm not sure if you want to know how to use the function or why your function doesn't work (as commented above). If it's the former, here's the answer:
You have to call it in one of the lifecycle instances. Most of the time, we call it in mounted().
...
methods: {
foo () {
// do something
},
},
mounted() {
this.foo();
},
...
In my vue.js application I send request by axios package in created() hook. I add response to array called coordinates. I want to use that array outside of created() hook. For example in mounted() hook or in functions which we can set in methods.
Right now when I tried to use self.coordinates outside created() hook it return undefined. When I use this.coordinates it return just [__ob__: Observer].
Whats wrong I did?
export default {
name: "Map",
data() {
return {
coordinates: [],
}
},
created() {
let self = this;
axios.get('URL').then(function (response) {
let coordinates = [];
for (let i = 0; i < response.data.length; i++) {
coordinates.push([response.data[i]["LATITUDE"], response.data[i]["LONGITUDE"]]);
}
self.coordinates = coordinates;
});
},
mounted() {
console.log(self.coordinates); // undefined
consol.log(this.coordinates); // [__ob__: Observer]
},
}
I would prefer "mounted" and move the logic into methods for reusability. The method can be kicked from anywhere afterwards. In the example below, I prefered kicking the method direcly. Watchers is another option.
Here is the fiddle https://jsfiddle.net/dj79ux5t/2/
new Vue({
el: '#app',
data() {
return {
coordinates: []
}
},
mounted() {
let self = this;
axios.get('https://api.weather.gov/').then(function (response) {
self.coordinates = response.data;
self.greet();
});
},
methods: {
greet: function () {
console.warn(this.coordinates.status);
}
}
})
I think instead of mounted , you should use watch . You call some link so it will take time to load that data , watch method will trigger when your data is updated ...
watch: {
coordinates: {
handler: function (updateVal, oldVal) {
console.log(updateVal)
},
deep: true
}
},
I have an issue where I want to retreive data from a child component, but the parent needs to use that data, before the child is mounted.
My parent looks like this
<template>
<component :is="childComp" #mounted="setData"/>
</template>
<script>
data : {
childComp : null,
importantData : null
},
methods : {
addComponent : function() {
this.prepareToAdd(this.importantData);
this.childComp = "componentA"; //sometimes will be other component
},
setData : function(value) {
this.importantData = value;
},
prepareToAdd : function(importantData){
//something that has to be run before childComp can be mounted.
}
}
</script>
My child (or rather, all the potential children) would contain something like this:
<script>
data : {
importantData : 'ABC',
},
created: function() {
this.$emit('mounted', this.importantData);
},
</script>
This clearly doesn't work - importantData is set when the childComponent is mounted, but prepareToAdd needs that data first.
Is there another way of reaching in to the child component and accessing its data, before it is mounted?
You can use $options to store your important data and have it available in beforeCreate. You can also use it to initialize a data item, and you can emit data items in created (you don't have to initialize from $options to emit in created, I'm just pointing out two things that can be done). The $options value is, itself, reactive (to my surprise) and can be used like any data item, with the added benefit that it is available before other data items.
new Vue({
el: '#app',
methods: {
doStuff(val) {
console.log("Got", val);
}
},
components: {
theChild: {
template: '<div>Values are {{$options.importantData}} and {{otherData}}</div>',
importantData: 'abc',
data() {
return {
otherData: this.$options.importantData
};
},
beforeCreate() {
this.$emit('before-create', this.$options.importantData);
},
created() {
this.$emit('on-created', this.otherData + ' again');
// It's reactive?!?!?
this.$options.importantData = 'changed';
}
}
}
});
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<the-child #before-create="doStuff" #on-created="doStuff"></the-child>
</div>
My bad :(
We cannot get the data inside beforeCreated() hook.
Use the beforeCreate() hook instead of created() hook:
beforeCreate: function() {
this.$emit('mounted', this.importantData);
},
We can use a watcher or computed option, so now your parent component would look:
data: {
childComp: null,
importantData: null,
isDataSet: false
},
methods: {
addComponent: function() {
this.prepareToAdd(this.importantData);
this.childComp = "componentA"; //sometimes will be other component
},
setData: function(value) {
this.importantData = value;
this.isDataSet = true;
},
prepareToAdd: function(importantData) {
//something that has to be run before childComp can be mounted.
}
},
watch: {
isDataSet: function(newValue, oldValue) {
if (newValue) {
this.addComponent();
}
}
}
I would suggest to use computed method as it caches the results. Use watcher when you have to perform asynchronous code.
I want to set data variable of Vue instance from component. Is that even possible.
Vue.component('graph', {
template: '',
props: {},
data: function () {
methods: {
setBtn: function () {
//here i want to set ShowBtn variable for example to false
},
}, this.getUserRecordStatistic();
});
new Vue({
el: '#app',
data: {
showBtn: null
},
methods: {},
});
This should do the trick:
Vue.component('graph', {
template: '',
props: {},
data: {},
methods: {
setBtn: function () {
app.showBtn = false;
},
},
});
var app = new Vue({
el: '#app',
data: {
showBtn: null
},
methods: {},
});
You can access data on the root vue instance through vm.$root.
setBtn: function () {
this.$root.showBtn = false;
},
As a best practice you should avoid directly setting params on other components. Vue is intended to decouple its components therefore directly editing a param, although possible, runs in the face of this. Check out the components guide for more info, specifically: https://v2.vuejs.org/v2/guide/components.html#Composing-Components
Therefore rather than directly editing this param you should emit an event from the component which you can listen for on the root - or any other component that sets the graph component, i.e.
graph component emit an event
Vue.component('graph', {
methods: {
activateBtn () {
this.$emit('set-button', true)
},
...
root or any component that sets graph in its template
# template
<graph #set-button="setBtn"></graph>
# script
new Vue({
el: '#app',
data: {
showBtn: false
},
methods: {
setBtn (state) {
this.showBtn = state
},
},
})