Creating an interactive star rating system with JSON data

Currently, I am in the process of developing a star rating system specifically designed for restaurant reviews. The 'Attributes' displayed on the user interface are dynamic and fetched in JSON format.

There exist five attributes with each having up to 5-star rating options available:

Review Attributes Data:

[
    {
      "ATTRIBUTEID": "FOODQUALITY",
      "ATTRIBUTENAME": "Quality Of Food",
      "POSITION": 1
    },
    {
      "ATTRIBUTEID": "CLEANLINESS",
      "ATTRIBUTENAME": "Cleanliness",
      "POSITION": 2
    },
    {
      "ATTRIBUTEID": "SERVICE",
      "ATTRIBUTENAME": "Service",
      "POSITION": 3
    },
    {
      "ATTRIBUTEID": "STAFFBEHAVE",
      "ATTRIBUTENAME": "Staf Behavior",
      "POSITION": 4
    },
    {
      "ATTRIBUTEID": "AMBIENCE",
      "ATTRIBUTENAME": "Ambience",
      "POSITION": 5
    }
  ];

The goal is to achieve something like this:

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

Progress So Far

This dynamic web page generates stars and labels automatically using JavaScript code. Clicking on one attribute's stars should not affect other attribute's ratings.

Edit

I have modified my snippet to create stars and labels dynamically based on the JSON data provided. However, there seems to be an issue where selecting stars from one attribute affects others. Please refer to the static HTML code for comparison.

In the second snippet below, I have included the JavaScript code responsible for generating these dynamic elements but struggling to maintain separate functionality for each attribute selected.

Problem: Changing the selection of stars once marked e.g., moving from 4 stars down to 2 stars, does not reset correctly across different attributes. The desired behavior is to mimic the functionality exhibited in the initial static HTML setup.

Answer №1

The issue with your second example is that the inputs in each form-group do not have the same name. To fix this problem, give them the same name.

Since your stars are set to float: right, you should append the stars in descending order to ensure they work as intended. Otherwise, the first star on the left will be assigned a value of 5.

I also simplified your code by using element properties instead of the setAttribute() method:

var data = [
  {
    "ATTRIBUTEID": "FOODQUALITY",
    "ATTRIBUTENAME": "Quality Of Food",
    "POSITION": 1
  },
  {
    "ATTRIBUTEID": "CLEANLINESS",
    "ATTRIBUTENAME": "Cleanliness",
    "POSITION": 2
  },
  {
    "ATTRIBUTEID": "SERVICE",
    "ATTRIBUTENAME": "Service",
    "POSITION": 3
  },
  {
    "ATTRIBUTEID": "STAFFBEHAVE",
    "ATTRIBUTENAME": "Staff Behavior",
    "POSITION": 4
  },
  {
    "ATTRIBUTEID": "AMBIENCE",
    "ATTRIBUTENAME": "Ambience",
    "POSITION": 5
  }
];

for (i = 0; i < data.length; i++){
  var container = document.getElementById("container");

  var row = document.createElement('div');
  row.className = "form-row";

  var commonLabel = document.createElement('label');
  commonLabel.className = "commonLable";
  commonLabel.innerHTML = data[i].ATTRIBUTENAME;

  var form_group = document.createElement('div');
  form_group.className = "form-group col-lg-12";

  for (j = 5;j > 0; j--) {
    var star = document.createElement("input");
    var label = document.createElement("label");
    star.type = "radio";
    star.id = data[i].ATTRIBUTEID + j;
    star.name = data[i].ATTRIBUTEID;
    star.className = "star star-" + j;
    star.value = j;
    label.className = "star star-" + j;
    label.htmlFor = data[i].ATTRIBUTEID + j;
    form_group.append(star, label);
  }

  row.append(commonLabel, form_group);
  container.appendChild(row);
}

$('#submit').click(function(){
  var formData = $('#container').serialize();
  alert(formData);
});
div.stars {
  width: 300px;
  display: inline-block;
}

.commonLable {
  margin-left: 55px;
  font-family: sans-serif;
  font-weight: bold;
}

input.star {
  display: none;
} 

label.star {
  float: right;
  padding: 5px;
  font-size: 30px;
  color: grey;
  transition: all .2s;
}

input.star:checked~label.star:before {
  content: '\2605';
  color: #FD4;
  transition: all .25s;
}

input.star-5:checked~label.star:before {
  color: #FE7;
  text-shadow: 0 0 20px #952;
}

input.star-1:checked~label.star:before {
  color: #F62;
}

label.star:hover {
  transform: rotate(-15deg) scale(1.3);
  cursor: pointer;
}

label.star:before {
  content: '\2605';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js"></script>
<div class="stars">
  <form action="" id="container">
   
  </form>
  <button type="button" id="submit">Submit</button>
</div>

Answer №2

Learn how to implement an interactive star rating system using JavaScript.

var data = [
          {
            "ATTRIBUTEID": "FOODQUALITY",
            "ATTRIBUTENAME": "Quality Of Food",
            "POSITION": 1
          },
          {
            "ATTRIBUTEID": "CLEANLINESS",
            "Quantity": "Cleanliness",
            "POSITION": 2
          },
          {
            "ATTRIBUTEID": "SERVICE",
            "Quantity": "Service",
            "POSITION": 3
          },
          {
            "ATTRIBUTEID": "STAFFBEHAVE",
            "Quantity": "Staf Behavior",
            "POSITION": 4
          },
          {
            "ATTRIBUTEID": "AMBIENCE",
            "Quantity": "Ambience",
            "POSITION": 5
          }
        ];

        for (v=0;v<data.length - 1;v++){
          var container = document.getElementById("container");

          var firstDiv = document.createElement('div');
          firstDiv.setAttribute("class", "form-row");

          var secondDiv = document.createElement('div');
          secondDiv.setAttribute("class", "commonLable");
          secondDiv.append(data[v].ATTRIBUTEID);


          var thirdDiv = document.createElement('div');
          thirdDiv.setAttribute("class", "form-group col-lg-12");

          /// append stars 

          for (i=0;i<5;i++){
            var incrementedVar = i+1;
            var stars = document.createElement("input");
            var label = document.createElement("label");
            stars.setAttribute("type", "radio");
            stars.setAttribute("id", '"'+ data[v].ATTRIBUTEID + i +'"');
            stars.setAttribute("name", '"'+ data[v].ATTRIBUTEID + i +'"');
            stars.setAttribute("class", "star star-5");
            label.setAttribute("class", "star star-5");
            label.setAttribute("for", '"'+ data[v].ATTRIBUTEID + i +'"');
            thirdDiv.append(stars, label);
          }

          secondDiv.append(thirdDiv);
          firstDiv.append(secondDiv);
          container.appendChild(firstDiv);
        }
div.stars {
          width: 300px;
          display: inline-block;
        }

        .commonLable {
          margin-left: 55px;
          font-family: sans-serif;
          font-weight: bold;
        }

        input.star {
          display: none;
        } 
        
        label.star {
          float: right;
          padding: 5px;
          font-size: 30px;
          color: grey;
          transition: all .2s;
        }

        input.star:checked~label.star:before {
          content: '\2605';
          color: #FD4;
          transition: all .25s;
        }

        input.star-5:checked~label.star:before {
          color: #FE7;
          text-shadow: 0 0 20px #952;
        }

        input.star-1:checked~label.star:before {
          color: #F62;
        }

        label.star:hover {
          transform: rotate(-15deg) scale(1.3);
          cursor: pointer;
        }

        label.star:before {
          content: '\2605';
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
        <link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js"></script>
        <div class="stars">
          <form action="" id="container">
        
          </form>
        </div>

Answer №3

Take a look at the corrected code snippet below, which includes added submit button for getting the result:

$(document).ready(function() {
  var data = [{
      "ATTRIBUTEID": "FOODQUALITY",
      "ATTRIBUTENAME": "Quality Of Food",
      "POSITION": 1
    },
    {
      "ATTRIBUTEID": "CLEANLINESS",
      "ATTRIBUTENAME": "Cleanliness",
      "POSITION": 2
    },
    {
      "ATTRIBUTEID": "SERVICE",
      "ATTRIBUTENAME": "Service",
      "POSITION": 3
    },
    {
      "ATTRIBUTEID": "STAFFBEHAVE",
      "ATTRIBUTENAME": "Staff Behavior",
      "POSITION": 4
    },
    {
      "ATTRIBUTEID": "AMBIENCE",
      "ATTRIBUTENAME": "Ambience",
      "POSITION": 5
    }
  ];

  for (var v = 0; v < data.length; v++) {

    var container = document.getElementById("container");

    var firstDiv = document.createElement('div');
    firstDiv.setAttribute("class", "form-row");

    var secondDiv = document.createElement('div');
    secondDiv.setAttribute("class", "commonLable");
    secondDiv.append(data[v].ATTRIBUTENAME);


    var thirdDiv = document.createElement('div');
    thirdDiv.setAttribute("class", "form-group col-lg-12");

    // append stars 

    for (var i = 1; i < data.length + 1; i++) {
      var incrementedVar = i + 1;
      var stars = document.createElement("input");
      var label = document.createElement("label");
      stars.setAttribute("type", "radio");
      stars.setAttribute("required", "required");
      stars.setAttribute("id", data[v].ATTRIBUTEID + i );
      stars.setAttribute("name",  data[v].ATTRIBUTEID ); 
      stars.setAttribute("class", "star star-5");
      stars.setAttribute("value", i);
      label.setAttribute("class", "star star-5");
      label.setAttribute("for",  data[v].ATTRIBUTEID + i);  
      thirdDiv.append(stars, label);

    }

    secondDiv.append(thirdDiv);
    firstDiv.append(secondDiv);
    container.appendChild(firstDiv);
    
  }
  var btn = document.createElement("button");
    btn.type = 'submit'; 
    btn.value= 'submit';
    btn.innerHTML = 'Submit'; 
    btn.setAttribute("style", "margin-left:55px;");
    container.append(btn);
  $('input:radio').change(
    function() {
    });
  $('.buttonSubmit').click(function(){
    var formData = $('#container').serialize();
    alert(formData);
  });
});
@charset "ISO-8859-1";
div.stars {
  width: 300px;
  display: inline-block;
  margin-left: -35px;
}

.commonLable {
  margin-left: 55px;
  font-family: sans-serif;
  font-weight: bold;
  margin-bottom: 0;
}

input.star {
  display: none;
}

label.star {
  float: right;
  padding: 5px;
  font-size: 40px;
  color: grey;
  transition: all .2s;
  margin-top: -25px;
}

hr {
  margin: 0;
}

input.star:checked~label.star:before {
  content: '\2605';
  color: #ffd309;
  transition: all .25s;
}

input.star-5:checked~label.star:before {
  color: #ffe840;
  text-shadow: 0 0 20px #952;
}

input.star-1:checked~label.star:before {
  color: #f24800;
}

label.star:hover {
  transform: rotate(-15deg) scale(1.3);
  cursor: pointer;
}

label.star:before {
  content: '\2605';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<div class="stars">
  <form action="" id="container">

  </form>
  
</div>

Answer №4

If I had initially marked the stars and now want to unmark them from 4 to 2, it doesn't seem to be working...

To change the stars back to their default state, you can use the following CSS rule:

input.star:checked~label.star:before {

This rule targets all the label.star elements that come after a checked checkbox.

To remove the yellow color, you just need to uncheck the sibling inputs. Here's how I did it using .siblings(selector) to select them and an .each() loop to set the checked property to false.

$(this).siblings("input").each(function() {
  $(this).prop("checked", false);
});

Here is a code snippet:

JavaScript code snippet
CSS code snippet
HTML code snippet

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

Monitoring Twitter bootstrap modal for scrollbar reaching the bottom

Currently, I am working with Twitter Bootstrap modal and facing a challenge in determining how to detect when the scrollbar of the modal reaches the bottom using either JavaScript or jQuery. https://i.stack.imgur.com/0VkqY.png My current approach involve ...

Troubles with deploying on Heroku

Every time I try to run my application on Heroku, all I see is: Heroku | Welcome to your new app! Refer to the documentation if you need help deploying. Because of this, I attempted to deploy my app to Heroku using this command: git push heroku master Ho ...

Struggling with a persistent Jquery AJAX problem despite numerous attempts to resolve it

<table class="table table-striped"> <thead> <tr> <th>Choose</th> <th>>Location</th> <th>Topic</th> & ...

When combining <a> with the class line-through, the line does not appear

I am currently utilizing a class to replace the deprecated strike in HTML: .entfall { text-decoration: line-through; } However, when using Firefox 38.x and the following code: <span class="entfall"><a href="some link">text</a></span ...

The extent of a nameless function when used as a parameter

I am currently developing a straightforward application. Whenever a user hovers over an item in the list (li), the text color changes to green, and reverts back to black when the mouse moves away. Is it possible to replace lis[i] with this keyword in the ...

Solving data within an Angular Controller

Recently delving into Angular development, I've found myself caught in a loop trying to solve this particular issue. To give some context, I'm utilizing the MEAN stack through mean.io which includes Angular UI Router functionalities. In my data ...

Secure access to an API using a certificate within a Vue.js application running on localhost

My vue.js app is built using vue-cli. The application is hosted at dev.example.com and the REST API can be found at dev.example.com/api/v1/. The backend has added an SSL certificate for security on the development environment. However, when I try to make a ...

The dropdown in MaterializeCSS does not display any data retrieved from VUE

Good evening. I am currently utilizing VUE along with MaterializeCSS. I have been trying to populate a selection menu without success. Although I am receiving the data from the database correctly, the options in the select tag remain blank when using V-F ...

What is the best way to display JQuery mobile tap event information in real-time?

I am experiencing an issue in my code where the tap event is being triggered, but the array[i] value is printed as null. Whenever I click on any index, it always prints an empty string (" "). Why does it display null instead of the clicked value? I am see ...

Synchronization-free API and callback functions

I am in need of utilizing an asynchronous service. My current approach involves sending data to this service using PHP and CURL, as well as receiving data from a URL provided by the service. How can I effectively respond or wait for feedback from this serv ...

What is the best location to insert the code for toggling the text on a button?

I'm looking to update the button text upon clicking. When the button is clicked, the icon changes accordingly. I want the text to change from "Add to list" to "Added to list". I attempted to implement this functionality with some code, but I'm un ...

Subdomain for an Ajax request

Can we use ajax requests to extract data from and fetch information from pages like ? It appears that JavaScript still does not permit subdomain requests. ...

Resolve background image alignment issue in Firefox browser for Bootstrap carousel

I am currently utilizing this particular bootstrap template. My goal is to have the carousel background images fixed, however, when I include the following CSS: background-attachment: fixed; like so: <div class="carousel-item active" style=&q ...

Bringing HTML into Excel with VSTO

I have encountered an issue while trying to import data from HTML files into Excel using VSTO (VB.NET). I am facing errors as I attempt to parse the HTML, and since I am new to this process, I need assistance in figuring out where my code is incorrect. I ...

I am constantly reminded by React hooks to include all dependencies

Imagine I am using useEffect to pre-fetch data upon initial rendering: function myComponent(props) { const { fetchSomething } = props; ... ... useEffect(() => { fetchSomething(); }, []); ... ... } My linter is warni ...

Having trouble getting JQuery Ajax POST to work in Codeigniter

Encountering an issue with jQuery AJAX post in CodeIgniter, where clicking the submit button triggers an error. Below is the code snippet: home.js form.on('submit', function(e){ e.preventDefault(); var fields = {}; form.find(' ...

Challenges arising from the rendering of main.js in Vue.js

Recently, I started working with Vue and am now faced with the task of maintaining a project. Main.js contains the routing structure: Main.js import Vue from 'vue' const app = new Vue({ el: '#app', data: { message: & ...

What is the best way to implement TrackballControls with a dynamic target?

Is there a way to implement the three.js script TrackballControls on a moving object while still allowing the camera to zoom and rotate? For example, I want to track a moving planet with the camera while giving the user the freedom to zoom in and rotate ar ...

The JavaScript code is attempting to execute a PHP script, however, I am struggling to parse the JSON data returned for use in the

As a novice, I am in the process of creating a JavaScript function that calls a PHP script every second. The PHP script retrieves values from MySQL DB, encodes them into JSON, which is then decoded by JS to display them on an HTML page. I have two queries ...

When scrolling, the body content covers up the navbar

Whenever I try to scroll the page, the body contents start overlapping with the navbar. I have content over the navbar that should disappear when scrolling, and it is working correctly. The navbar should be fixed while scrolling, and this functionality ...