I'm making a shopping cart system with Laravel and Vue. When I add an item to the basket, I display a confirmation message by toggling a Vue variable being watched by a v-if:
<div class="alert alert-success" v-if="basketAddSuccess" transition="expand">Added to the basket</div>
And the JS:
addToBasket: function(){
item = this.product;
this.$http.post('/api/buy/addToBasket', item);
this.basketAddSuccess = true;
}
(And yes, I will be adding this in a then-catch shortly).
This works fine and the message appears. However, I'd like the message to disappear again after a certain time, say a few seconds. How can I do this with Vue? I've tried setTimeOut
but Vue doesn't seem to like it, saying it's undefined.
EDIT: I was misspelling setTimeout
like an idiot. However, it still doesn't work:
My function is now:
addToBasket: function(){
item = this.photo;
this.$http.post('/api/buy/addToBasket', item);
this.basketAddSuccess = true;
setTimeout(function(){
this.basketAddSuccess = false;
}, 2000);
}
The best and simplest way to solve this problem is by using an arrow function () => {}
:
addToBasket() {
var item = this.photo;
this.$http.post('/api/buy/addToBasket', item);
this.basketAddSuccess = true;
// now 'this' is referencing the Vue object and not the 'setTimeout' scope
setTimeout(() => this.basketAddSuccess = false, 2000);
}
This works because the this
of arrow functions is bound to the this
of its enclosing scope- in Vue, that's the parent/ enclosing component. Inside a traditional function called by setTimeout
, however, this
refers to the window
object (which is why you ran into errors when you tried to access this.basketAddSuccess
in that context).
Another way of doing this would be passing this
as an arg to your function through setTimeout
's prototype using its setTimeout(callback, delay, arg1, arg2, ...)
form:
addToBasket() {
item = this.photo;
this.$http.post('/api/buy/addToBasket', item);
this.basketAddSuccess = true;
//Add scope argument to func, pass this after delay in setTimeout
setTimeout(function(scope) {
scope.basketAddSuccess = false;
}, 2000, this);
}
(It's worth noting that the arg passing syntax is incompatible with IE 9 and below, however.)
Another possible, but less eloquent and less encouraged, way is to bind this
to a var outside of setTimeout
:
addToBasket() {
item = this.photo;
this.$http.post('/api/buy/addToBasket', item);
this.basketAddSuccess = true;
//Declare self, which is accessible inside setTimeout func
var self = this;
setTimeout(function() {
self.basketAddSuccess = false;
}, 2000);
}
Using an arrow function would eliminate the need for this extra variable entirely however, and really should be used unless something else is preventing its use.