Determine the percentage variance for each item within an array and showcase it in a data table using Vue Vuetify

My data source is a JSON file structured as follows:

{"USD": {"7d": 32053.72, "30d": 33194.68, "24h": 31370.42}, "AUD": {"7d": 43134.11, "30d": 44219.00, "24h": 42701.11}, "RUB": {"7d": 2451451.45, "30d": 2465896.74, "24h": 2398589.80},  "JPY": {"7d": 3537735.55, "30d": 3664620.47, "24h": 3472632.46}, "BRL": {"7d": 167555.18, "30d": 169473.27, "24h": 163054.93}, "ILS": {"7d": 108658.72, "30d": 111663.67, "24h": 106988.58}, "GBP": {"7d": 23257.66, "30...

In my Vuetify table component, I aim to automate the calculation for the thirtyDaysDiff column instead of manually performing it for each object in the array. The calculation logic is functional, but repeated manual entries are tedious.

How can I apply the same computation method uniformly across all objects in the array without individual input?

The formula utilized is as shown below:

 calculateThirtyDayDifference() {
    let calculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[0]['7d'] - this.bitcoinInfo[0]['30d'] ) / ( (this.bitcoinInfo[0]['7d']+this.bitcoinInfo[0]['30d'])/2 ) )
    let roundedCalculatedPercent = Math.max( Math.round(calculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
    this.bitcoinInfo[0].thirtyDaysDiff = roundedCalculatedPercent

    let secondCalculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[1]['7d'] - this.bitcoinInfo[1]['30d'] ) / ( (this.bitcoinInfo[1]['7d']+this.bitcoinInfo[0]['30d'])/2 ) )
    let secondRoundedCalculatedPercent = Math.max( Math.round(secondCalculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
    this.bitcoinInfo[1].thirtyDaysDiff = secondRoundedCalculatedPercent
}

An attempt was made using a forEach loop which did not yield desired results. Below is the complete component code:

<template>
<div>
  <v-data-table
    :headers="headers"
    :items="bitcoinInfo"
    :hide-default-footer="true"
    :class="{active: group && item.id == group.id}"
  >

  </v-data-table>
</div>

</template>

<script>
import axios from 'axios';

  export default {
    data () {
      return {
        bitcoinInfo: [],
        headers: [
          {
            text: 'Currency',
            align: 'start',
            value: 'currency',
          },
          
          { text: '30 Days Ago', value: '30d' },
          { text: '30 Day Diff %', value: 'thirtyDaysDiff'},
          { text: '7 Days Ago', value: '7d' },
          { text: '7 Day Diff %', value: 'sevenDaysDifference' },
          { text: '24 Hours Ago', value: '24h' },
        ],
      }
    },

    methods: {
      getBitcoinData() {
        axios
      .get('data.json')
      .then((response => {

      var convertedCollection =  Object.keys(response.data).map(key => {
            return {currency: key, thirtyDaysDiff: 0, sevenDaysDifference: 0,  ...response.data[key]}
          })

          this.bitcoinInfo = convertedCollection
          
      }))
      .catch(err => console.log(err))
        },

        calculateThirtyDayDifference() {
            let calculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[0]['7d']  - this.bitcoinInfo[0]['30d'] ) / ( (this.bitcoinInfo[0]['7d']+this.bitcoinInfo[0]['30d'])/2 ) )
            let roundedCalculatedPercent = Math.max( Math.round(calculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
            this.bitcoinInfo[0].thirtyDaysDiff = roundedCalculatedPercent


            let secondCalculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[1]['7d']  - this.bitcoinInfo[1]['30d'] ) / ( (this.bitcoinInfo[1]['7d']+this.bitcoinInfo[0]['30d'])/2 ) )
            let secondRoundedCalculatedPercent = Math.max( Math.round(secondCalculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
            this.bitcoinInfo[1].thirtyDaysDiff = secondRoundedCalculatedPercent

           
        }
      },
           
      mounted() {
        this.getBitcoinData()
      },
      updated() {
         this.calculateThirtyDayDifference()
      }
  }

</script>

Answer №1

I suggest utilizing a slot and dynamically calculating the values for display.

Vuetify gives you the flexibility to customize how a specific column's cells are rendered using the slot item.<column-key-name> (I personally prefer using the #slotName syntax, but v-slot:slotName works just as well):

<template #item.thirtyDaysDiff="{ item }">
  {{ calculateThirtyDayDifference(item) }}%
</template>

This approach allows us to pass each row's data (via the slot's item property) to the calculation function, and then showcase the calculated value for each row by invoking the function for each row.

The drawback of this method is that the function will be re-executed and recalculated with every render, but for basic computations, this shouldn't lead to any performance concerns.


Below is a complete working example using your sample data:

new Vue({
  // ## Required for snippet only ##
  el: '#app', template: '#app-template', vuetify: new Vuetify(),
  // #########
  data() {
    return {
      bitcoinInfo: [],
      headers: [{text:"Currency",align:"start",value:"currency"},{text:"30 Days Ago",value:"30d"},{text:"30 Day Diff %",value:"thirtyDaysDiff"},{text:"7 Days Ago",value:"7d"},{text:"7 Day Diff %",value:"sevenDaysDifference"},{text:"24 Hours Ago",value:"24h"}],
    }
  },
  methods: {
    calculateThirtyDayDifference(item) {
      let calculatedPercent = 100 * Math.abs((item['7d'] - item['30d']) / ((item['7d'] + item['30d']) / 2));
      return Math.max(Math.round(calculatedPercent * 10) / 10, 2.8).toFixed(2);
    }
  },
  computed: {
    thirtyDayDiffArray() {
      return 1;
    },
  },
  mounted() {
    // Load sample data
    let sampleData = JSON.parse('{"USD": {"7d": 32053.72, "30d": 33194.68, "24h": 31370.42}, "AUD": {"7d": 43134.11, "30d": 44219.00, "24h": 42701.11}, "RUB": {"7d": 2451451.45, "30d": 2465896.74, "24h": 2398589.80},  "JPY": {"7d": 3537735.55, "30d": 3664620.47, "24h": 3472632.46}, "BRL": {"7d": 167555.18, "30d": 169473.27, "24h": 163054.93}, "ILS": {"7d": 108658.72, "30d": 111663.67, "24h": 106988.58}, "GBP": {"7d": 23257.66, "30d": 23838.55, "24h": 22923.17}, "PLN": {"7d": 124869.61, "30d": 127872.57, "24h": 122668.16}, "CAD": {"7d": 40425.62, "30d": 41444.76, "24h": 39827.13}, "EUR": {"7d": 27187.74, "30d": 27955.81, "24h": 26659.79}}');
    this.bitcoinInfo = Object.keys(sampleData)
      .map(key => ({
        currency: key,
        sevenDaysDifference: 0,
        ...sampleData[key]
      })
    );
  },
})
<!-- Import Vuetify and Vue for snippet -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/@mdi/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="75131a1b0135415b0d">[email protected]</a>/css/materialdesignicons.min.css" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5d2b282929343b241d6f7325">[email protected]</a>/dist/vuetify.min.css" rel="stylesheet"><script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="097f7c6c493b2771">[email protected]</a>/dist/vue.min.js"></script><script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f4828191809d928db4c6da8c">[email protected]</a>/dist/vuetify.js"></script>

<!-- Target container for Vue to render into -->
<div id="app"></div>

<!-- Template that Vue will use --> 
<script type="text/x-template" id="app-template">
  <v-app>
    <v-data-table
      :headers="headers"
      :items="bitcoinInfo"
      :hide-default-footer="true"
    >
      <template #item.thirtyDaysDiff="{ item }">
        {{ calculateThirtyDayDifference(item) }}%
      </template>
    </v-data-table>
  </v-app>
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Encountering an issue with AngularJS where the selected ng-model value is

I'm utilizing plain options for the select tag because I only need to display a few options when they meet a certain condition. In order to perform other operations, I require the value of the selected dropdown in the controller. However, the issue is ...

Twice the fetch is triggered

I've implemented a simple JavaScript function that handles fetching a URL and updating the HTML page upon receiving a response. Here's an example of how it works: function postToDatabase(self) { // other code here async function postData() ...

What is the step-by-step process for incorporating the `module` module into a Vue project?

ERROR Compilation failed with 6 errors 16:20:36 This specific dependency could not be located: * module in ./node_modules/@eslint/ ...

Modify the contents of the 'data-content' area in the popover

Looking for a solution where I can update only a portion of the data-content within a popover. Here is an example code snippet: <div class="popover-wrapper"> <i class="glyphicon glyphicon-question-sign hover_content" ...

Unable to establish a connection between two localhost servers

I'm encountering an issue with my API and React application setup. The API is running on localhost:3001, while the React app is on localhost:3000. Despite being able to make requests using Postman, I keep getting blocked by CORS policy when trying to ...

Build a Docker container for a project that requires utilizing yarn link for dependencies

While working on my NextJS project, I made the decision to utilize yarn as my package manager and utilized yarn link for import aliases/absolute imports. This feature of yarn is quite handy and is recommended for managing aliases within a project. However, ...

Encountering an undefined property error while trying to access index '0' in Angular 6 with Angular Material's mat-radio-group component, specifically when attempting to set a dynamic variable within

Currently, I am working with Angular 6 and Angular Material. My project involves a dynamic list of polls with various options. I am attempting to display the selected option using two-way data binding. However, due to the dynamic nature of my list, I have ...

Invoke a function from within an event handler

Is there a way to trigger a function once an event has been completed? For example - $('.class').slideUp('fast', function() { // execute the function }); ...

Incorrect scroll position being updated

My current project involves dynamically adding a class to the DOM based on scroll position. If the scroll position is 150 or above, a class is added, and if it's less than 150, the class is removed. Everything works fine when scrolling down, but when ...

Achieving a dynamic "Picture Presentation" feature with JavaScript/jQuery

Currently, I am in the process of developing a website that will serve as a presentation. My plan is to create a slideshow effect using JavaScript. While I have implemented some functions, I must admit that it is not very organized at the moment. The main ...

How can I add navigation dots to my slider?

I've been experimenting with my slider and I managed to make it slide automatically. However, the issue is that there is no option to manually navigate through the slides. I am looking to add navigation dots at the bottom so users can easily switch be ...

Sub properties are being systematically removed from the data as it travels from the Node/Express server to the React client

An unforeseen issue is occurring during data transmission from the server to the client, causing the loss of data from sub-properties before any action can be taken on it. This issue cannot be replicated elsewhere, as data querying and retrieval functions ...

Fusion of Laravel and Vue component

I am trying to connect a Vue component using a tag MyComponent.vue <template> <div> <h1>Hey there!</h1> </div> </template> <script> export default { } </script> This is the content of app. ...

Encountering an undefined error for 'orderBy' while running tests on a Vue component that utilizes lodash in combination with Jest

Using Vue.js, I have successfully imported lodash into my main.js file like so: import lodash from 'lodash' Vue.use(VueLodash, lodash) Now, within my single file components, I am able to utilize the lodash orderBy function with ease: this._.or ...

Tips for postponing the appearance of the background image within a div tag

Check out my fiddle here. I am looking to create an effect where the "background-image:" in the CSS loads fully and displays after a 3-second delay with a quick fade-in effect. Until then, the entire div should be in black color. How can this be achie ...

Using a function as a variable within jQuery's .click() method

Currently, I am utilizing a tabbed interface that is being managed by a jQuery function to handle the click events of my tabs. $(document).ready(function () { $('a#foo').click(function() { //content, various calls return fal ...

Trouble installing NPM packages from Artifactory on Windows 10

Problem Description: I am utilizing Artifactory for my NPM packages. When attempting to install them on "Windows - 7", everything is functioning correctly. However, on "Windows - 10" an error is being displayed and the packages are not installing. Error M ...

When a button is triggered, it should initiate a click event on an input in TypeScript

I have created a color picker that is visible on a page. When clicked, it displays a dropdown menu of colors for selection. However, my objective is to hide the color picker initially and only reveal it when a specific button is clicked. This way, the dro ...

How can I restrict the amount of data shown in an array in Vue.js?

I have an array of data values that I need to display in sets of two, with a "show more" button to reveal the next set. For example, initially displaying values 0 and 1, then revealing values 2 and 3 when the button is clicked. Check out the code snippet ...

Retrieving AJAX content once it has finished loading

Apologies for my poor English. I have a function to handle ajax requests like this: $(document).on("click", ".ajax", function(e){ //dynamic content here, getting the href value from links. }); Now I need to manipulate the content of the ajax response AF ...