Reputation: 3536
My app is declared like this in app.js
Vue.component('sale', require('./components/Sale.vue'));
const app = new Vue({
el: '#app',
data: {
showModal: false
},
});
My main index.blade file @yields the content of my view, and this view simply contains my custom component like this
<sale v-if="showModal" @hide="showModal=false"></sale>
As you can see, its using the showModal
to determine when it shows the modal form on top of the main page.
The component in brief is declared here with the form submit option:
<template name="sale">
<form class="form-horizontal" role="form" action="/sales/save" method="POST" @submit.prevent="save">
This save method is called correctly and the axios post is working successfully.
I have a standard form inside the modal page and the methods are declared here, which u can see uses axios to post to my controller - again, the post is successful.
methods: {
close(){
this.$emit('hide');
},
save(){
console.log('SOLD');
console.log(this.$data);
axios.post('/sales/save', this.$data)
.then(function (response) {
this.$emit('hide');
})
.catch(function(error) {
console.log('NO ' , error);
});
}
}
The close method also works as I expect, using the emit to change the value of showModal
, closing the dialog.
What is not working, is after the post, the .then
function is giving me an error with the same call to emit: TypeError: Cannot read property '$emit' of undefined
.
In fact, the .catch
is catching the error with the emit inside the .then
function (not what i was expecting - that it would be catching axios POST errors).
Essentially i'm not sure how to close the modal in the same manner, once the axios call is successful.
Edit: added:
mounted() {
const self = this;
}
and changed emit reference
self.$emit('hide');
I'm not sure i understand the rest of that post
Upvotes: 0
Views: 3891
Reputation: 18136
You assume this
refers to Vue instance, but it's not the case in your callback. You lose the this
reference in a regular function.
You can preserve this
using one of the following solutions:
1) Use arrow function:
methods: {
fetchData: function() {
axios.get('https://jsonplaceholder.typicode.com/posts/1')
.then(text => console.log(this)) // Vue instance
}
}
2) Save this
to a variable:
methods: {
fetchData: function() {
const self = this; // save reference
axios.get('https://jsonplaceholder.typicode.com/posts/1')
.then(function(text) {
console.log(self) // Vue instance; 'this' points to global object (Window)
})
}
}
Upvotes: 4
Reputation: 32704
Considering you are using ES2015, you can simply use an arrow function to make sure you don't create a new this
context:
axios.post('/sales/save', this.$data)
.then(response => {
this.$emit('hide');
})
.catch(error => {
console.log('NO ' , error);
});
You can find out more about arrow functions at: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Upvotes: 3
Reputation: 21485
The reason the code in your update didn't work is that your self
is scoped inside mounted()
, but you're trying to use it inside methods.save()
.
This would work:
methods: {
save() {
var self = this;
axios.post('/sales/save', this.$data)
.then(function (response) {
self.$emit('hide');
})
//...
Or if you're using an ES6 transpiler you could use arrow functions to avoid the scoping problem altogether (arrow functions don't bind their own this
.)
methods: {
save() {
axios.post('/sales/save', this.$data)
.then((response) => {
this.$emit('hide');
})
Upvotes: 1