Using Vuex to calculate the percentage of values within an array of objects and dynamically updating this value in a component

I'm currently in the process of developing a voting application with Vuex.

Within the app, there are buttons for each dog that users can vote for. I have successfully implemented functionality to update the vote count by clicking on the buttons:

store.js
export const store = new Vuex.Store({
    state: {
        dogs: [
            { id: 0, name: 'Dog1', vote: 0, percentage: 0 },
            { id: 1, name: 'Dog2', vote: 0, percentage: 0 },
            { id: 2, name: 'Dog3', vote: 0, percentage: 0 },
            { id: 3, name: 'Dog4', vote: 0, percentage: 0 },
            { id: 4, name: 'Dog5', vote: 0, percentage: 0 }
        ]
    },
    getters: {      
      dogs: state => {
            return state.dogs;
        },
    },
    mutations: {
      vote: (state, payload) => {
        const index = state.dogs.findIndex(dog => dog.id === payload);
        state.dogs[index].vote++;                
      },

    },
    actions: {
      voteAction(store, payload) {
        store.commit('vote', payload)
      },
    }
})
Button.vue
<template>
    <div v-for="(dog, index) in dogs" :key="index">
        <button type="button" @click="vote(dog.id)">{{ dog.name }}</button>
    </div>
</template>

<script>
import { mapGetters } from 'vuex';
import { mapMutations } from 'vuex';

export default {
  computed: {
    dogs() {
        return this.$store.getters.dogs
    }
  },
  methods: {
    vote(id) {
        this.$store.dispatch('voteAction', id);
    },
  }
}
</script>

My next goal is to calculate the percentage of votes for each dog and update all their percentages accordingly. This could potentially be achieved by:

  1. Obtaining the total number of votes
  2. Calculating the vote percentage for each dog
  3. Updating all the percentages

Although I am struggling to write this logic in the methods section of the store.js file. Additionally, I intend to receive the updated percentages in the Result.vue component.

<template>
Result.vue
<div v-for="(dog, index) in dogs" :key="index">
    <div 
        class="progress-bar" 
        role="progressbar" 
        :style="{width: dog.percentage + '%'}"
        aria-valuenow="dog.percentage" 
        aria-valuemin="0" 
        aria-valuemax="100"
        >{{ dog.name }} {{ dog.percentage }}% ({{ dog.vote }} votes)</div>
</div>
</template>

<script>
export default {
  computed: {
    dogs() {
        return this.$store.getters.dogs
    },
  },
}
</script>

How should I go about retrieving all the updated percentages from store.js to display in Result.vue?

Answer №1

In my opinion, it may be a good idea to remove the percentage attribute from state data as it does not seem like it belongs directly to the state since its value is calculated based on other state data values. Instead, you could use getters to calculate a dog's percentage like so:

getters: {
    dogs: state => {
      return state.dogs;
    },
    percentage: (_state, getters) => dog => {
      const totalVotes = getters.totalVotes;
      return totalVotes ? (100 * dog.vote) / totalVotes : 0;
    },
    totalVotes: state =>
      state.dogs.reduce((count, dog) => (count += dog.vote), 0)
  }

As a result, you would now need to map the percentage getter in your Vue component. Instead of accessing dog.percentage, you would call percentage(dog) instead.

Answer №2

Your progress on solving the main issue is commendable. To further enhance your store.js functionality, consider making the following modifications and test for improved performance: For a demonstration without CSS styling, visit:

To access the code on GitHub, refer to: https://github.com/manojkmishra/dogvoting

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
state: {dogs: [
{ id: 0, name: 'Dog1', vote: 0, percentage: 0 },
{ id: 1, name: 'Dog2', vote: 0, percentage: 0 },
{ id: 2, name: 'Dog3', vote: 0, percentage: 0 },
{ id: 3, name: 'Dog4', vote: 0, percentage: 0 },
{ id: 4, name: 'Dog5', vote: 0, percentage: 0 }
] , totalvotes:0,
},
getters: {    
dogs: state => {   return state.dogs;  },
},
mutations: {vote: (state, payload) => {
const index = state.dogs.findIndex(dog => dog.id === payload);
state.dogs[index].vote++; 
state.totalvotes++;
for (let j=0;j< state.dogs.length; j++) 
{let per= (100 * state.dogs[j].vote)/state.totalvotes;
  state.dogs[j].percentage=per;
}
},
},
actions: {voteAction(store, payload) {
store.commit('vote', payload)
},
},
modules: {  }
})

Answer №3

If I were to integrate my store.js data into Result.vue, it would look something like this:

<template>
 <div v-for="(dog, index) in allDogs" :key="index">
  <div 
    class="progress-bar" 
    role="progressbar" 
    :style="{width: dog.percentage + '%'}"
    aria-valuenow="dog.percentage" 
    aria-valuemin="0" 
    aria-valuemax="100"
    >{{ dog.name }} {{ dog.percentage }}% ({{ dog.vote }} votes)
  </div>
 </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  computed: {
    ...mapGetters({
        allDogs: "dogs"
    })
  },
}
</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

"Enjoying a table header that scrolls freely with autoscroll feature

Resolved - http://jsfiddle.net/CrSpu/11704/ I'm facing an issue with a table that has autoscroll functionality. I am looking to freeze the header of the table when automatic scrolling occurs, or you can test it out using my code pen. I'm uncer ...

Add some texture to one side of the quadrilateral

I have a project in threejs where I need to display an image of a cat within a rectangle. The challenge is to render the right half of the rectangle in red, while displaying the full stretched image of the cat on the left half. Here's my current scen ...

Error with replacing regular expressions in IE11 for the variable $0

Having both a string and a message: str = "Test $0 $1 $2"; message = "Hi %2 Hello %2" ; The goal is to replace all occurrences of %2 with str in the message using RegExp, like so: message = message.replace(new RegExp("%2" , "g"), str); While this works ...

The object _plugins_vuetify__WEBPACK_IMPORTED_MODULE_8__.default does not contain a constructor function

https://i.sstatic.net/Cqx5B.pngAfter attempting to add Vuetify to my project, I encountered an issue despite trying different solutions from various sources. Below is the code snippet from my vuetify.js file: import Vue from 'vue' import Vuetify ...

What is the best way to generate an array of objects by extracting specific properties from another array object?

Here is the information provided: const cocktail = [ { "idDrink":"13070", "strDrink":"Fahrenheit 5000", "strGlass":"Shot glass", "strInstructions":&qu ...

Javascript promise failing to deliver

As a beginner in the world of JavaScript development, I am excited to be part of the stackoverflow community and have already gained valuable insights from reading various posts. Currently, I am facing an issue where I need to load a file, but due to its ...

Error message: JavaScript JSON variable undefined in AWS Lambda

My lambda function is being triggered by an IoT rule that sends a MQTT message in JSON format. I am facing an issue where the top level fields are logging correctly, but when it comes to nested objects in the JSON, they appear as "undefined". Even after tr ...

What benefits does Laravel gain from including Vue? (Exploring the synergy between SPA and MVC)

I'm feeling a bit perplexed about why the Laravel framework comes with Vue.js included. From what I know, Laravel follows a traditional MVC pattern, whereas Vue is typically used for building single page applications (SPAs). These are two different a ...

Is it feasible to incorporate a third-party JavaScript file into a React application?

I have a JavaScript file from a previous MVC project that generates a basic table using ExtJS. Currently, I'm working on developing a new React application with a navigation bar and sidebar. My goal is to explore the possibility of importing the exis ...

Discovering pairs of numbers that are not next to each other in an array that has not been

When working with an array of unsorted numbers, the goal is to identify and extract pairs of elements that are not consecutive. Input [2,3,4,5,9,8,10,13] Desired output (2,5)(8,10)(13,13) To achieve this: Input = [2,3,4,5,9,8,10,13] If we arrange the num ...

Can one iterate over a JavaScript object using forEach() even if the keys are undefined?

During a code review, I came across the following code: var a = { ... }; // an object filled with key-value pairs for (var key in a) { if (!angular.isUndefined(key)) { do.stuff(); } } I am questioning whether key can ever be undefined or ...

What steps should I take to export a function from a React functional component in order to create a reusable library?

Currently, I am in the midst of developing a React component library and one of my components contains a function that I want to export. The purpose of the addParticle function is to enable users of the library to dynamically insert particles into a cont ...

How can I toggle the visibility of a div based on whether a variable is defined or not?

How can I display a specific div on my webpage only when certain variables in PHP pull out a specific result from a database? I attempted to use the code snippet below, but it's not working as expected. Can someone provide guidance on how to achieve ...

The browser failed to display the SVG image, and the console log indicated that the promise was rejected, with the message "false."

I'm struggling to understand why my SVG isn't showing up on the screen. The console log is displaying "false," which I believe indicates that a promise was rejected Here is the TypeScript file I am working with: export class PieChartComponent im ...

Customize the inline click event using jQuery

I have a navigation with links that resemble the following: <a id="navform" href="#" tabindex="-1" onclick="mojarra.ab(this,event,'action','@form','content');return false" class=" ...

Display a div using Jquery when hovering over it with several classes

I want to create a hover effect where div2 fades in slowly when hovering over div1 within the same container. However, my jQuery code doesn't seem to be working as expected... $(".div").hover(function() { $(this).find(".div2").animate({ opac ...

Command field in Javascript

I've crafted an exquisite search box for my website, but I'm struggling to make it functional and display search results. Below are the Html and CSS files pertaining to this section of my site: .searchbox{ /*setting width of the form eleme ...

The findOne() function is providing the complete model instead of a specific document as expected

When using findOne() to extract a document, the correct result is printed when the returned value is logged. However, when looping over it, the model is printed instead of the original document stored in the City table: { _id: 62e135519567726de42421c2, co ...

Combine several elements in a single jQuery scrollreveal function

I am currently working on a webpage that utilizes the jQuery library plugin scrollreveal to gradually reveal different html elements when the page loads. The functionality of the code is working correctly at the moment, but I have noticed that there is a d ...

The router link is unable to redirect to the desired page

neither the static router nor the dynamic router can navigate to the page. Here is the HTML code: <router-link to="/add_peer">Test</router-link> <router-link :to="{path:'/add_peer'}">Test</router-link> ...