Vue.js calling a method with setTimeout is not working [duplicate] - vue.js

I'm creating a component with Vue.js.
When I reference this in any of the the lifecycle hooks (created, mounted, updated, etc.) it evaluates to undefined:
mounted: () => {
console.log(this); // logs "undefined"
},
The same thing is also happening inside my computed properties:
computed: {
foo: () => {
return this.bar + 1;
}
}
I get the following error:
Uncaught TypeError: Cannot read property 'bar' of undefined
Why is this evaluating to undefined in these cases?

Both of those examples use an arrow function () => { }, which binds this to a context different from the Vue instance.
As per the documentation:
Don’t use arrow functions on an instance property or callback (e.g. vm.$watch('a', newVal => this.myMethod())). As arrow functions are bound to the parent context, this will not be the Vue instance as you’d expect and this.myMethod will be undefined.
In order to get the correct reference to this as the Vue instance, use a regular function:
mounted: function () {
console.log(this);
}
Alternatively, you can also use the ECMAScript 5 shorthand for a function:
mounted() {
console.log(this);
}

You are using arrow functions.
The Vue Documentation clearly states not to use arrow functions on a property or callback.
Unlike a regular function, an arrow function does not bind this. Instead, this is bound lexically (i.e. this keeps its meaning from its original context).
var instance = new Vue({
el:'#instance',
data:{
valueOfThis:null
},
created: ()=>{
console.log(this)
}
});
This logs the following object in the console:
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
Whereas... If we use a regular function (which we should on a Vue instance)
var instance = new Vue({
el:'#instance',
data:{
valueOfThis:null
},
created: function(){
console.log(this)
}
});
Logs the following object in the console:
hn {_uid: 0, _isVue: true, $options: {…}, _renderProxy: hn, _self: hn, …}

If you want to keep using the arrow function, you could pass the component instance (this) as parameter like :
computed: {
foo: (vm) => { //vm refers to this
return vm.bar + 1;
}
}

you cannot use the arrow funtion if you want to use the this. Because the arrow funtion doesn't bind this.

Related

Vue.js setup() and mounted()

I am fairly new to Vue.js and am currently working on a project. I currently have some constants declared in setup(), lets call one of the constant "c", and I want to get them from within mounted(). I realized that I can still console.log(this.c) within mounted() to get the constant printed out but when I try to console.log(this.c) within a function in mounted() I can no longer get it and I get an error Uncaught (in promise) TypeError: Cannot read properties of undefined.
Why is this so? And what work arounds are there?
Example:
setup() {
const c = ref(1)
},
mounted() {
console.log(this.c) // prints 1 on console
function doesSomething() {
console.log(this.c) // TypeError: Cannot read properties of undefined
...
}
}
The function doSomething in the mounted hook should be declared with an arrow function instead, since function declaration has its own this binding:
mounted() {
console.log(this.c)
const doesSomething = () => {
console.log(this.c) // Ok
}
}
mounted is an option in the options api which is different than the composition api using the setup hook, you could use onMounted hook in setup to replace mounted option:
import {onMounted} from 'vue';
setup(){
let c='some content'
onMounted(()=>{
console.log(c)// don't use this keyword
})
}

Access instance via methods inside a custom Vue component

I'm trying to access the instance methods/data through a triggered method inside a custom registered Vue component.
Below a basic example:
Vue.component('example-component', {
template: `<div>
<h2>Count: {{count}}</h2>
<button class="btn btn-primary" v-on:click="increment()">Increment</button>
</div>`,
data: () => {
return {
count: 0
}
},
methods: {
increment: () => {
console.log("Click!");
console.log("Current count: ", this.count);
this.count++;
console.log("New count: ", this.count);
},
decrement: () => {
// other function
}
},
mounted: () => {
console.log("Example component mounted!");
}
});
Results:
Example component mounted!
Click!
Current count: undefined
New count: NaN
As you might notice the property 'count' has been loaded during the component mount and is available/rendered inside the HTML. The method 'increment()' has also been triggered. However, 'this.count' seems to be unreachable like possible other methods (e.g. 'this.decrement()') which will throw a TypeError this.decrement is not a function.
Any suggestions if this approach is even possible?
PS. I'm aware of the default approach via a .vue file registery like:
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Explanation from the official docs:
Vue automatically binds the this value for methods so that it always refers to the component instance. This ensures that a method retains the correct this value if it's used as an event listener or callback. You should avoid using arrow functions when defining methods, as that prevents Vue from binding the appropriate this value.
The answer above by Phoenix seems to be valid, and I can only add that you can write the functions in a short form too like:
increment() { ... },
decrement() { ... }
which looks nicer in my opinion, although there is a slight difference.
Arrow functions don't bind with this. Use normal functions instead for your methods.
increment: function() { ... },
decrement: function() { ... }

Computed property that depends on another computed property

Code below yields error "Cannot read property 'form' of undefined":
computed: {
boundary_limits () {
return this.$refs.hemoBoundaryLimits.form;
},
high_risk_alerts () {
return this.$refs.highRiskAlerts.form;
},
alerts () {
return {
boundary_limits: this.boundary_limits,
high_risk_alerts: this.high_risk_alerts
}
}
}
Yet if I removed alerts(), I get no error and I can even console log boundary_limits or high_risk_alerts
successfully, which means $refs.hemoBoundaryLimits and this.$refs.highRiskAlerts are defined.
So Vue.js has a problem with how I define alerts, but I see no problem in it.
Any clue what's going on?
The error comes because you are trying to access $refs in computed property.
Computed properties are evaluated before the template is mounted and thus the hemoBoundaryLimits is undefined.
You should access $refs in the mounted hook.
As solution, you can trick it by knowing when the component is mounted using #hook event:
<hemoBoundaryLimits #hook:mounted="isHemoBoundaryLimitsMounted = true" />
And in the script
data: () => ({
isHemoBoundaryLimitsMounted: false
}),
computed: {
boundary_limits () {
if (!this.isHemoBoundaryLimitsMounted) return
return this.$refs.hemoBoundaryLimits.form;
}
}

Vue-resource not recognize in project [duplicate]

I'm creating a component with Vue.js.
When I reference this in any of the the lifecycle hooks (created, mounted, updated, etc.) it evaluates to undefined:
mounted: () => {
console.log(this); // logs "undefined"
},
The same thing is also happening inside my computed properties:
computed: {
foo: () => {
return this.bar + 1;
}
}
I get the following error:
Uncaught TypeError: Cannot read property 'bar' of undefined
Why is this evaluating to undefined in these cases?
Both of those examples use an arrow function () => { }, which binds this to a context different from the Vue instance.
As per the documentation:
Don’t use arrow functions on an instance property or callback (e.g. vm.$watch('a', newVal => this.myMethod())). As arrow functions are bound to the parent context, this will not be the Vue instance as you’d expect and this.myMethod will be undefined.
In order to get the correct reference to this as the Vue instance, use a regular function:
mounted: function () {
console.log(this);
}
Alternatively, you can also use the ECMAScript 5 shorthand for a function:
mounted() {
console.log(this);
}
You are using arrow functions.
The Vue Documentation clearly states not to use arrow functions on a property or callback.
Unlike a regular function, an arrow function does not bind this. Instead, this is bound lexically (i.e. this keeps its meaning from its original context).
var instance = new Vue({
el:'#instance',
data:{
valueOfThis:null
},
created: ()=>{
console.log(this)
}
});
This logs the following object in the console:
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
Whereas... If we use a regular function (which we should on a Vue instance)
var instance = new Vue({
el:'#instance',
data:{
valueOfThis:null
},
created: function(){
console.log(this)
}
});
Logs the following object in the console:
hn {_uid: 0, _isVue: true, $options: {…}, _renderProxy: hn, _self: hn, …}
If you want to keep using the arrow function, you could pass the component instance (this) as parameter like :
computed: {
foo: (vm) => { //vm refers to this
return vm.bar + 1;
}
}
you cannot use the arrow funtion if you want to use the this. Because the arrow funtion doesn't bind this.

Calling a function with a paramater in click causes error

I have a computed Vue function that has a parameter. Every time I try to bind it to the click, I receive and error Error in event handler for "click": "TypeError: searchHashtag is not a function"
Here's the HTML:
<el-button #click="searchHashtag('#acc')">Test</el-button>
And here's the logic:
data () {
messages: []
},
mounted () {
api.fetchMessages( this.projectId, ( data ) => {
this.messages = data.messages;
},
computed: {
searchHashtag (searchBy) {
if (_.contains(this.messages, searchBy))
this.$message('This is a message.');
}
}
You want a method, not a computed property.
methods: {
searchHashtag (searchBy) {
if (_.contains(this.messages, searchBy))
this.$message('This is a message.');
}
}
Computed properties cannot be called like a function. They act like properties of the Vue and do not take arguments. When you need a function that accepts arguments, always use a method.