VueJS not responding to change in array length?

Viewed 1895

Using a single-file template, I would like to have a button that shows "click here" if an array is empty and shows the value if it is populated. The ajax is working fine and the object is getting updated, but the button doesn't re-render. What am I doing wrong here?

<template>
  <span>
    <button
      v-if="value.app_token.length"
      class="btn btn-outline-primary btn-sm"
      disabled
    >Mobile App Token: {{ value.app_token[0].token }}</button>
    <button v-else class="btn btn-primary btn-sm" @click="getToken">Click to get Mobile App Token</button>
  </span>
</template>

<script>
module.exports = {
  props: ["value"],

  methods: {
    getToken() {
      axios
        .get("/patients/getToken/" + this.value.id)
        .then(response =>
          this.value.app_token.splice(
            0,
            this.value.app_token.length,
            response.data
          )
        )
        .catch(error => console.log(error));
    }
  }
};
</script>
3 Answers

The getToken method mutates the value prop, which is not allowed (you may have an error in the console).

Solution

Create a computed for the token and a variable to hold the fetched data:

data() {
  return {
    fetched: null
  }
},
computed: {
  token() {
    let token = JSON.parse(JSON.stringify(this.value.app_token));
    if (this.fetched) {
      // Now this mutates a copy, not the original
      token.splice(0, token.length, this.fetched);
    }
    return token;  
  }
}

If nothing has been fetched, the token value will be the same as in the prop. Otherwise, it will recalculate to the modified token. Change your getToken method so that its purpose is to store the data result in fetched:

methods: {
  getToken() {
    axios
      .get("/patients/getToken/" + this.value.id)
      .then(response => this.fetched = response.data)
      .catch(error => console.log(error));
  }
}

Now use the computed in your v-if:

v-if="token.length"

And display it like:

{{ token[0].token }}

Here is a demo for you

Also, this would be much less confusing if the token prop was just the token string by itself instead of part of a complex object, and then also pass the axios id as a separate prop.

Change the condition to

v-if="value.app_token && value.app_token.length >0"

If the value.app_token in an empty array, then there will be a length of 0 which will make the condition true.

Related