简体   繁体   中英

How to fetch the data from API first then re-mount the barchart component

I am currently making a dashboard page and currently struggling how to render the datasets to the Bar chart. I have no problems showing static data to the chart, but when I use API data, it does not work. I read solutions about using watchers. But I am confused how to solve it if my Barchart is in another component. I have some data returning from API like: governerate: [total_sent_applications, active_members, name] which I should display. but, I guess the bar chart component is mounting to the dom before accessing the data. so, the data with bar charts appears and when reload browser suddenly disappears.

Parent Component:

<template>
    <div class="row">
      <div class="col-xl-12 col-md-6 col-sm-12">
         <bar-chart
           :active-members="active"
           :name="governorateName"
           :total-sent-applications="sent_applications"
         />
     </div>
  </div>
</template>

<script>
import BarChart from "@/components/UI/BarChart.vue";

export default {
  components: {
    AppCard,
    BarChart,
  },
  data() {
    return {
      chartData: [],
      active: [],
      governorateName: [],
      sent_applications: [],
    };
  },
  created() {
    this.chartData = this.$store
      .dispatch("home/fetchAllData") // function that loads data from api
      .then((response) => { // the returned data from api
        this.sent_applications = response.data.data.governerate.map(
          (el) => el.total_sent_applications
        );
        this.governorateName = response.data.data.governerate.map(
          (el) => el.name_ar
        );
        this.active = response.data.data.governerate.map(
          (el) => el.active_members
        );
      })
  },
};
</script>

Child Component: (BarChart.vue)

    <template>
      <div class="card">
        <div
          class="
            card-header
            d-flex
            justify-content-between
            align-items-sm-center align-items-start
            flex-sm-row flex-column
          "
        ></div>
        <div class="card-body">
          <canvas
            id="myChart"
            class="bar-chart-ex chartjs"
            data-height="600"
          ></canvas>
        </div>
      </div>
    </template>
    
    <script>
    import Chart from "chart.js";
    
    export default {
      name: "BarChart",
    
      props: {
        activeMembers: {
          type: Array,
          default: null,
        },
        name: {
          type: Array,
          default: null,
        },
        totalSentApplications: {
          type: Array,
          default: null,
        },
      },  
      mounted() {
        const ctx = document.getElementById("myChart").getContext("2d");
        const chart = new Chart(ctx, {
          type: "bar",
          data: {
            labels: this.name,
            datasets: [
              {
                label:
                  this.$t("total_sent_applications") || "Total Sent Applications",
                data: this.totalSentApplications,
                backgroundColor: "rgba(71, 183, 132, 0.5)",
                borderColor: "#47b784",
                borderWidth: 1,
              },
              {
                label: this.$t("active_members") || "Active Members",
                data: this.activeMembers,
                backgroundColor: "rgba(255, 255, 0, 0.5)",
                borderColor: "#255255",
                borderWidth: 1,
              },
            ],
          },
          options: {
            barValueSpacing: 10,
            responsive: true,
            lineTension: 1,
            scales: {
              xAxes: [
                {
                  label: "chart",
                  ticks: {
                    beginAtZero: false,
                    padding: 5,
                  },
                },
              ],
              yAxes: [
                {
                  label: "chart",
                  ticks: {
                    beginAtZero: false,
                    padding: 10,
                  },
                },
              ],
            },
          },
        });
      },
    };
</script>

If you only need to fetch data once and then have it displayed in the chart you can achieve it with v-if or with the Vue key attribute. The below code snipped should work for you.

<template>
    <div class="row">
      <div class="col-xl-12 col-md-6 col-sm-12">
         <bar-chart
          :key="sent_applications.length"
           v-if="dataFetched"
           :active-members="active"
           :name="governorateName"
           :total-sent-applications="sent_applications"
         />
     </div>
  </div>
</template>

<script>
import BarChart from "@/components/UI/BarChart.vue";

export default {
  components: {
    AppCard,
    BarChart,
  },
  data() {
    return {
      chartData: [],
      active: [],
      governorateName: [],
      sent_applications: [],
      dataFetched: false
    };
  },
  created() {
    this.chartData = this.$store
      .dispatch("home/fetchAllData") // function that loads data from api
      .then((response) => { // the returned data from api
        this.sent_applications = response.data.data.governerate.map(
          (el) => el.total_sent_applications
        );
        this.governorateName = response.data.data.governerate.map(
          (el) => el.name_ar
        );
        this.active = response.data.data.governerate.map(
          (el) => el.active_members
        );
        this.dataFetched = true
      })
  },
};
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM