16

I'm having a little trouble setting one of my this. values within my Vue.js application. I believe I'm either not understanding async axios calls correctly, or how async works within Vue.js.

I have the following three methods:

updateAvailability(availability) {
    if (availability == true) {
        this.showYourDetails();
    } else {
        this.showBookingDetails();
    }
},
checkAvailability: async function(event) {
    event.preventDefault();
    const availability = await this.handleAvailabilityRequest(event);
    this.loading = true;
    console.log(availability); //This evaluates to undefined
    const availabilityUpdate = await this.updateAvailability(availability);
    this.loading = false;
},
handleAvailabilityRequest: async function(event) {
    event.preventDefault();
    let valid = this.validateFieldsForAvailabilityRequest(); //Ignore this for this particular question, assume valid is always true

    if (valid) { // This is true
        let config = {
            headers: {
                "X-CSRFToken": this.csrfToken,
                "Content-Type": 'application/x-www-form-urlencoded',
            }
        }

        let formData = new FormData();
        let reservationTime = this.reservationHourSelected + ':' + this.reservationMinuteSelected;

        formData.set('type', 'availability_request');
        formData.set('session_name', this.sessionName);
        formData.set('reservation_party_size', this.reservationPartySize);
        formData.set('reservation_date', this.reservationDate);
        formData.set('reservation_time', reservationTime);

        await axios.post('{{ request_absolute_uri }}', formData, config).then(function(response) {
            this.availabilityMessage = response.data.message;
        }).catch(function(error) {
            this.availabilityMessage = false;
            console.log(error);
        });
    }
    return this.availabilityMessage;
}

My response.data.message is being passed back from my framework as True/true but it seems I'm not returning anything from the await this.handleAvailabilityRequest() function? The post definitely hits the server as logging shows everything I want - then returns back message = true in json response context.

So, I guess ... help! Completely dumbfounded as to why this isn't working other than it being an issue with waiting for the promise...

4
  • You should be using an arrow function here, otherwise you won't get the correct context. Commented Jun 15, 2018 at 9:08
  • Vivick is right, or add .bind(this) at the end of your error callback function. Commented Jun 15, 2018 at 9:11
  • since you are updating "this" availabilityMessage, I don't see a point in returning it in the request. Instead check this.availabilityMessage in the further calls down from there instead of availability. Commented Oct 22, 2019 at 14:27
  • You're also mixing async await with a standard promise. This can cause problems I've found. Either use one or the other. I prefer async/await for these situations, but i have also found times where i have to use a Promise.all on awaited calls. Commented Oct 22, 2019 at 14:30

2 Answers 2

26

The problem is here:

await axios.post('{{ request_absolute_uri }}', formData, config).then(function(response){
  this.availabilityMessage = response.data.message;
}).catch(function (error) {
  this.availabilityMessage = false;
  console.log(error);
});

Because you're using a full-fledged function, your this inside the .then does not refer to the instantiated object. Use an arrow function instead so that the this is inherited from the outer scope:

await axios.post('{{ request_absolute_uri }}', formData, config)
.then((response) => {
  this.availabilityMessage = response.data.message;
}).catch((error) => {
  this.availabilityMessage = false;
  console.log(error);
});
Sign up to request clarification or add additional context in comments.

6 Comments

This worked like a charm. With a few modifications the outer scope is now changing. Just out of interest, why does this work?
With standard functions, this inside of any function is the calling context of that function - with your original code, that was the Promise returned by .post. With arrow functions, the this is always inherited from the outer scope, rather than depending on the calling context of the arrow function.
If you must use function() you can always bind the parent context (this) with bind. function() {}.bind(this)
You can also use the good ol’ let vm = this (or var if you need to go extreme) at the very beginning of the method and use it in place of this.
if using Then , there's still need of using await ?
|
24

Why use promises pattern if you are using async await. This removes the use of callbacks and this binding being lost

You can do it like this

handleAvailabilityRequest: async function (event) {
  event.preventDefault();
    ...

  try{
   let response =  await axios.post('{{ request_absolute_uri }}', formData, config)
      this.availabilityMessage = response.data.message;
  }catch(error) {
      this.availabilityMessage = false;
      console.log(error);
    };
  }
  return this.availabilityMessage;
}

You can use try/catch block for handling errors when using async/await

5 Comments

"Why use promises if you are using async await" — Because an async function returns a promise and await can only wait for a function that returns a promise.
axios does return a promise
@Quentin we can await on that promise being resolved and return the response
"finally" is a great way to clean up after a try catch. I use it all the time
This is a better answer IMHO. async/await is a game changer. Avoiding those chained functions for promises defintely makes this cleaner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.