What is the method for calculating the total number of votes in a review, and subsequently determining the average?

So I've encountered a situation where I'm working in a Vue context with Laravel as the backend. On my homepage, I have a select option for searching musicians based on their genre. Now, when I navigate to this page, I want each musician card to display stars corresponding to the average votes they have received.

However, I'm facing challenges when it comes to manipulating the votes within the template and I am clueless about how to handle it in the methods section. It seems like a simple task but I'm having difficulty with it.

Here's a visual representation of the problem highlighted in red

https://i.sstatic.net/PrwP3.jpg

And here's the code snippet:

FilteredMusicians.vue

In this section, I iterate through the musicians array obtained from the Laravel endpoint. To retrieve the votes, I loop through each musician.reviews object to access the review.vote property. The challenge lies in aggregating all the votes and calculating the average.

<template>
  <div class="container">
    <div class="row py-4">
      <div
        v-for="musician in musicians"
        :key="musician.id"
        class="col-xs-12 col-md-4 col-lg-4 my-4"
      >
        <div class="card">
          <div class="musician-img">
            <img
              :src="'/storage/' + musician.cover"
              :alt="musician.stagename"
            />
          </div>
          <div class="card-body text-center">
            <h5 class="card-title py-2">{{ musician.stagename }}</h5>
            <!-- reviews -->
            <div v-for="review in musician.reviews" :key="review.id">
              {{ review.vote }}
            </div>
            <!-- /reviews -->
            <router-link
              class="btn btn-orange text-white"
              :to="{ name: 'musician', params: { slug: musician.slug } }"
              >View Profile</router-link
            >
          </div>
        </div>
      </div>
    </div>
    <div class="text-center">
      <router-link class="btn btn-orange text-white mb-3" :to="{ name: 'home' }"
        >Go Back</router-link
      >
    </div>
  </div>
</template>

<script>
export default {
  name: "FilteredMusicians",

  data() {
    return {
      musicians: [],
    };
  },

  methods: {
    getMusicians(slug) {
      axios
        .get(`http://127.0.0.1:8000/api/musicians/${slug}`)
        .then((res) => {
          res.data.forEach((el) => {
            this.musicians = el.musicians;
          });
        })
        .catch((err) => {
          console.log(err);
        });
    },
    
  },

  created() {
    this.getMusicians(this.$route.params.slug);
  },
};
</script>

This function is used to retrieve all musicians related to a specific genre

public function filterMusicians($slug) {

        $genres = Genre::where('slug', $slug)->with('musicians')->get();

        return response()->json($genres);
    }

Below is the Musician model where I utilized protected $with to fetch the reviews of each musician filtered by genre

class Musician extends Model
{
    protected $fillable = [
        'user_id', 
        'stagename',
        'slug', 
        'description',
        'bio',
        'services',
        'typology',
        'cover'
    ]; 

    protected $with = [
        'reviews'
    ];

    public function user() {
        return $this->hasOne('App\User'); 
    }

    public function genres() {
        return $this->belongsToMany('App\Genre'); 
    }

    public function sponsorships() {
        return $this->belongsToMany('App\Sponsorship')->withPivot('end_date'); 
    }

    public function messages() {
        return $this->hasMany('App\Message'); 
    }

    public function reviews() {
        return $this->hasMany('App\Review');
    }
}

Lastly, we have the Review model defined below

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Review extends Model
{
    protected $fillable = [
        'name',  
        'email', 
        'review', 
        'vote', 
        'musician_id'
    ]; 

    public function musician() {
        return $this->belongsTo('App\Musician')->with('reviews'); 
    }
}

Answer №1

Personally, I lean towards React as my preferred framework, but it appears quite clear what steps you need to take here. Start by creating a new function below your existing getMusicians method, name it getAverageVotes. This is how I envision the implementation:

getAverageVotes(reviews) {
  const sum = reviews.reduce((acc, review) => acc += review.vote, 0)
  return sum / reviews.length
}

In your template, replace this:

<div v-for="review in musician.reviews" :key="review.id">
  {{ review.vote }}
</div>

with the following:

<div>
  {{ getAverageVotes(musician.reviews) }}
</div>

Answer №2

Would you like to find the average of music reviews with ease?

You can achieve this by creating a specialized method.

calculateReviewAverage(reviews: any[]) {
  if (reviews.length == 0) return 0;
  else {
    return reviews.reduce((a, b) => a + b.vote, 0) / reviews.length;
  }
}

Next step is to adjust the code that displays the review votes.

{{calculateReviewAverage(musician.reviews)}

If you want a more in-depth explanation on how reduce works, check out the link below.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

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

Column Visibility: What is the best way to organize columns?

Here is the code I currently have that is working: http://jsfiddle.net/tarabyte/s8Qds/3/ Javascript: $(function() { (function generateStyleSheet(len){ var styles = [], i = 0; for(; i < len; i++) { styles.push('.hide-' + ...

Displaying Errors from Controllers in React Hook Forms

Currently, I am attempting to generate required errors for my input element that is enclosed within a Controller component from react-hook-form version 7. The Input consists of a Material-UI TextField structured like this; <Controller ...

Transforming precise military time using Angular and Javascript filtering

There are a few times where I find myself liking 01:45 //and 15:00 I believe this time format is HH:MM in military time? While I have come across some advanced functions that can parse sentences and even include seconds like HH:MM:SS, I am looking for a ...

JS - Activate the ghost element feature by using the preventDefault function

I am currently working on a project where I need to drag elements from a list of img tags to various svg:rect containers. The process involves using mousedown and mouseup events to track which img is being picked from the list and where it is dropped with ...

Enhance the Antd Datepicker by including an additional button in the footer or modifying the functionality of the "Now" button

Is there a way to enhance my Date and Time picker by adding an additional button for users to quickly jump to a specific request date without inputting the time? I am looking to streamline the user experience, but I am not satisfied with the appearance of ...

Using enums in templates - The statement will constantly evaluate to 'true' because the categories of 'RequestStatus.Done' and 'RequestStatus.Rejected' do not intersect at all

My HTML code is in this format, and I want to check the value to display a different form based on certain conditions. I have set up the condition in my HTML like this: requestStatus = RequestStatus; <ng-container *ngIf=" (model.lastStat ...

Issue encountered while attempting to utilize the concat method to condense an array

Describing the Problem: I am facing a challenge with flattening an array of sales data. Each element in the array contains an ID, sale code, seller username, timestamp, and details which include an array of products, quantities, and subtotals for each item ...

Reorganize external dependencies in the wwwroot directory using gulp

In my development setup using VS 2015, ASP.net vnext, Angular 2, Typescript, and gulp.js, I have successfully automated the process of moving my scripts/**/*.ts files to the wwwroot/app folder. Now, I am looking to extend this automation to include my libr ...

My VW controller is receiving null from AJAX

Hey there, I've been dealing with this issue for a few hours now and still haven't found a solution. All my request data looks good except for subscriptionTag, as it always comes back as null when the request is sent to the server. I even tried ...

Modify an element upon clicking the mouse on an image

I am looking to dynamically change the paragraph element with className="details" to an editable input field when a user clicks on the image with className="edit-icon" within the same grid container. How can I achieve this functionality ...

Is it possible that the JSON is formatted correctly but there is an issue with parsing it in JavaScript?

const plantDisease={ "apple_scab": { "symptoms": "Leaves covered in a dark velvet layer, showing velvety olive-green to black spots", "cause": "Venturia inaequalis", "natural_control": "Utilize resistant varieties like Prima, Priscilla, Sir P ...

Creating three-dimensional text in Three.js

My script is based on this documentation and this resource. Here is an excerpt of my code: <script src="https://raw.github.com/mrdoob/three.js/master/build/three.js"></script> <script> var text = "my text", height = 20 ...

Tips for centering a bootstrap card on the screen using reactjs

I've been struggling to keep my card centered on the screen despite using align-items and justify-content. I've researched on various websites to find a solution. //Login.js import React, { Component } from 'react'; import './App ...

Tips for splitting lengthy text into multiple lines in Vue

Vue is being used to display a line which appears lengthy when displayed in one line. I'm interested in splitting this long line into multiple lines automatically. Can someone guide me on how this can be achieved? <span class="text-xs"> ...

Using the boolean result from an array in Vue3 with v-if

I encountered an issue with handling content visibility in my project. I needed to toggle the visibility of content using v-if, but the content was stored in an array. Here is an example of what I had: <v-expansion-panel v-for="item in flightOptio ...

Identify picture quality?

I've been looking into this but haven't found a solution yet. Is there a way to determine an image's resolution using an upload file field? Currently, I can only find the pixel dimensions of an image...but I need to know its size in "inches ...

What is the best way to integrate Parse user authentication as middleware in a Node Express application?

As I work on my Express app and implement user login and registration with Parse, I am facing a challenge in creating a middleware function to verify if users are logged in for specific pages like the user account page. Currently, I have some code that re ...

What is the process for calculating and determining the exact area the div should be released?

I am currently developing a drag-and-drop application using only Javascript. I have successfully implemented the dragging functionality, allowing elements to be moved randomly within the page. However, I now face the challenge of creating a drop zone with ...

Vue and axios join forces to send requests and showcase the outcomes

I am in the process of setting up a Vue application that will send a request to a backend and then showcase the response on the webpage. I created this example: new Vue({ data: { message: '{}' }, el: '.login-app', } ...

Get rid of an element in a Javascript array and show the updated array contents

In the following code block, I have implemented a simple functionality that allows me to display a list of items from an array, remove a selected item from the list, and then display the updated list without the deleted item. var carBrands = ["Toyota", "H ...