TajC
TajC

Reputation: 45

How can I have the spinner load only before the data

I'm trying to have my Spinner component show only before the API data is loaded, otherwise, it should be hidden. I created a variable called value and set it to true whenever the API info is fetched but I seem to be getting it wrong when using the v-if and v-else directives. At the moment only one component is loaded when using the v-if.

What am I doing wrong?

I'm new to Vue.js and I've seen the directive called v-cloak but I'm not particularly sure how to use it.

<template lang="">
    <div>
        <Header />
        <Spinner v-if="!value" />
        <CryptoList v-else v-bind:crypts="cryptoData" />
    </div>
</template>
<script>
    import Header from "./components/Header";
    import CryptoList from "./components/CryptoList";
    import Spinner from "./components/Spinner";
    import axios from "axios";
    const API_KEY = "ed599676c60cb5b0b369519d8cadaa8a";

    export default {
        data: function() {
            return {
                cryptoData: [],
                value: null
            };
        },
        name: "App",
        components: {
            Header,
            CryptoList,
            Spinner
        },
        methods: {
            isMounted() {
                return (this.value = false);
            }
        },
        mounted() {
            axios
                .get(`https://api.nomics.com/v1/currencies/ticker?key=${API_KEY}`, {
                    params: {
                        "per-page": "100",
                        "page": 1,
                        "rank": 1
                    }
                })
                .then((response) => {
                    this.cryptoData = response.data;
                    console.log(response.data);
                })
                .catch(function(error) {
                    console.log(error);
                });

            this.value = true;
            console.log(this.value);
        }
    };
</script>
<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-size: 16px;
    }
    body {
        font-family: "Baloo 2";
        font-weight: lighter;
        color: #e7e7de;
        background-image: url("./img/background.jpg");
        background-repeat: no-repeat;
        background-attachment: fixed;
    }
</style>

Upvotes: 1

Views: 461

Answers (1)

tao
tao

Reputation: 90068

You're setting this.value = true before the API call returns. You have to do it after:

mounted() {
  axios
   .get(...)
     .then((response) => {
        this.cryptoData = response.data;
        // <= here the API call returned (you're inside the promise)
        this.value = true;
     });
  // <= here API call has not returned yet. (you're outside the promise)
  //    you're in mounted, right after the API call was made
}

An alternative approach is to turn value into a computed returning true/false based on current value of cryptoData's length:

data: () => ({
   cryptoData: []
}),
computed: {
  value() {
    return !!this.cryptoData.length;
  }
},
mounted() {
  axios
    .get(...)
       .then((response) => {
         this.cryptoData = response.data;
       });
}

Whenever you want to show the spinner again, all you have to do is empty cryptoData:

this.cryptoData = [];

I would also advise you to work on your naming practices (as a general rule, naming variables or properties value, what, when, who, some, few, is considered bad practice). Good practice is using descriptive names, announcing the role or the function performed. In this case, I'd rename value to hasData or maybe isLoadingData. Good coding and naming practices will save you time, money, hair, even jobs.

Upvotes: 1

Related Questions