6
votes

I'm working on a dashboard with multiple 'modules' that each have their own API calls. Most of the endpoints are snappy but there is a couple that can take a few seconds.

I have a filtering option for date range and every time that changes I re run the API calls for the data.

The issue is that I don't want the user to be able to stack up the API calls if they keep changing their date range quickly before the others have loaded.

Im using a single file vue component, and have a method for each API call and then a single method that groups and calls these.

watch: {
    dateFilter: function() {
        this.initStatModules();
    }
},
methods: {
    getCustomers: function() {
        var $this = this;
        return axios.get(`/api/v1/reports/${$this.team.id}/stats-dashboard/customers?date=${$this.dateFilter}`).then(function(response) {
            $this.customers = response.data;
        });
    },
    getBookings: function() {
        var $this = this;
        return axios.get(`/api/v1/reports/${$this.team.id}/stats-dashboard/bookings`).then(function(response) {
            $this.bookings = response.data;
        });
    },
    getTotalRevenue: function() {
        var $this = this;
        return axios.get(`/api/v1/reports/${$this.team.id}/services-revenue?date=${$this.dateFilter}`).then(function(response) {
            $this.totalRevenue = response.data.data.totalRevenue;
        });

    },
    initStatModules: function() {
        this.getCustomers();
        this.getBookings();
        this.getTotalRevenue();
    }
}

What I wish to be able to do is cancel all the pending API requests in the watch or initStatModules method.

Looking at the axios docs: https://github.com/axios/axios#cancellation it is supported, but I cannot get my head around how to implement it as I wish.

Thanks!

2

2 Answers

0
votes

I would suggest to avoid the calls instead of cancelling, Axios says that it is implemented on a draft and in this situation it looks like avoiding calls would be enough.

What I mean by that:

Don't let the user filter if is there a filter call happening. You need to use async/await or Promises to have a better control for that also.

for example, one data property like:

isFiltering: false

Using promises like you did (omitting your code here, but it's the same idea for the others methods) :

methods: {
  getCustomers: async function () {
      var $this = this;
      this.isFiltering = true;
      return axios.get(`/api/v1/reports/${$this.team.id}/stats-dashboard/customers?date=${$this.dateFilter}`).then(function(response) {
          $this.customers = response.data;
          $this.isFiltering = false;
      });
  }
}

In your HTML use the isFiltering to disable(adding CSS or anyway you wish) the input. That would prevent the user to change the filtering and will look like the filtering is executing. Remember to add the .catch part to set the isFiltering to false if something went wrong. Using .finally if is available would be even better

if isFiltering then disable

Another way would be to use Throttle from Lodash or any other solution, or this implementation suggested here on S.O.: Simple throttle in js

That throttle option is just better to avoid consecutive calls, like when the user is typing in an input.

0
votes
<template>
  <input type="date" :disabled="isDisabled" v-model="dateFilter">
</template>

<script>
export default {
  data () {
    return {
      dateFilter: null,
      modulesLoaded: 0,
      isDisabled: false
    }
  },
  watch: {
    dateFilter () {
      this.initStatModules()
    }
  },
  methods: {
    getCustomers () {
      axios.get(`/api/v1/reports/${$this.team.id}/stats-dashboard/customers?date=${$this.dateFilter}`)
        .then(response => {
          this.customers = response.data
          this.onModuleLoaded()
        })
    },
    getBookings () {
      axios.get(`/api/v1/reports/${$this.team.id}/stats-dashboard/bookings`)
        .then(response => {
          this.bookings = response.data
          this.onModuleLoaded()
        })
    },
    getTotalRevenue () {
      axios.get(`/api/v1/reports/${$this.team.id}/services-revenue?date=${$this.dateFilter}`)
        .then(response => {
          this.totalRevenue = response.data.data.totalRevenue
          this.onModuleLoaded()
        })
    },
    initStatModules () {
      this.isDisabled = true
      this.modulesLoaded = 0
      this.getCustomers()
      this.getBookings()
      this.getTotalRevenue()
    },
    onModuleLoaded () {
      this.modulesLoaded++
      if (this.modulesLoaded === 3) {
        this.isDisabled = false
      }
    }
  }
}
</script>

try this.