jQuery Novice to Ninja: User Rating Project

Below is the code, word for word from the book’s exercise files.

The code builds a system for users to rate their favorite celebrities based on 1-4 stars. Each half star is represented by an HTML radio button, which are each replaced with <a> tags, using background images for the stars.

Everything seems to work fine except that when you click a star/radio button, all subsequent radio buttons are assigned the “checked” attribute. If this were for a real application, and the data was being saved, additional logic would be needed to find the actual radio button/rating the user selected.

This snippet of code is what assigns the “checked” attribute:

 $allLinks
        .parent()
        .find('input:radio[value=' + $star.text() + ']')
        .attr('checked', true);

Unless I’m missing something in the remainder of the code, I don’t see why this is adding the checked attribute to all lesser radio inputs as well.

Entire code:

$(document).ready(function(){
 starRating.create('.stars');
});

// The widget
var starRating = {
  create: function(selector) {
    // loop over every element matching the selector
    $(selector).each(function() {
      var $list = $('<div></div>');
      // loop over every radio button in each container
      $(this)
        .find('input:radio')
        .each(function(i) {
          var rating = $(this).parent().text();
          var $item = $('<a href="#"></a>')
            .attr('title', rating)
            .addClass(i % 2 == 1 ? 'rating-right' : '')
            .text(rating);

          starRating.addHandlers($item);
          $list.append($item);

          if($(this).is(':checked')) {
            $item.prevAll().andSelf().addClass('rating');
          }
        });
        // Hide the original radio buttons
        $(this).append($list).find('label').hide();
    });
  },
  addHandlers: function(item) {
    $(item).click(function(e) {
      // Handle Star click
      var $star = $(this);
      var $allLinks = $(this).parent();

      // Set the radio button value
      $allLinks
        .parent()
        .find('input:radio[value=' + $star.text() + ']')
        .attr('checked', true);

      // Set the ratings
      $allLinks.children().removeClass('rating');
      $star.prevAll().andSelf().addClass('rating');

      // prevent default link click
      e.preventDefault();

    }).hover(function() {
      // Handle star mouse over
      $(this).prevAll().andSelf().addClass('rating-over');
    }, function() {
      // Handle star mouse out
      $(this).siblings().andSelf().removeClass('rating-over')
    });
  }

}

Can you post your radio button HTML?

Sure. Here it is.

<!doctype html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
	<title>StarTrackr!</title>
	
	<link rel="stylesheet" href="../../css/base.css" type="text/css" media="screen" charset="utf-8"/>
  <link rel="stylesheet" href="stars.css" type="text/css" media="screen" charset="utf-8"/>

	<script src="../../lib/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
	<script type="text/javascript" src="script.js"></script>
</head>
<body>
	<div id="container">
		<div id="header">
			<h1>StarTrackr!</h1>
    </div>
		<div id="content">
		  <h2>Celebs</h2>
      <h3 >Glendatronix</h3>
      <p>
        Rate this celebrity:
      </p>
      <form action="">
        <div class="stars">
          <label for="rating-1"><input id="rating-1" name="rating" type="radio" value="1"/>0.5 Stars</label>
          <label for="rating-2"><input id="rating-2" name="rating" type="radio" value="2"/>1 Star</label>
          <label for="rating-3"><input id="rating-3" name="rating" type="radio" value="3"/>1.5 Stars</label>
          <label for="rating-4"><input id="rating-4" name="rating" type="radio" value="4"/>2 Stars</label>
          <label for="rating-5"><input id="rating-5" name="rating" type="radio" value="5"/>2.5 Stars</label>
          <label for="rating-6"><input id="rating-6" name="rating" type="radio" value="6"/>3 Stars</label>
          <label for="rating-7"><input id="rating-7" name="rating" type="radio" value="7"/>3.5 Stars</label>
          <label for="rating-8"><input id="rating-8" name="rating" type="radio" value="8"/>4 Stars</label>
        </div>
        <div>
          <input type="submit" value="Submit Rating" />
      	</div>
      </form>
		</div>

		<div id="footer">
			<p>
				&copy; Copyright 2010 CelebriTracker Productions
			</p>
		</div>
	</div>
</body>
</html>

Thank you,

Not sure if it is a mis-print or an issue with the code you wrote, but the following line

 $allLinks
        .parent()
        .find('input:radio[value=' + $star.text() + ']')
        .attr('checked', true);

Needs to be replaced with:

      $allLinks
        .parent()
          .find('label:contains(' + $star.text() + ') input:radio')
        .attr('checked', true);

The code was from the source files that came from the book. They should’ve ran the final edits by you first, because your fix took care of the problem.

Thanks for the quick fix!

Not a problem. If you have any troubles with other pieces of it, feel free to post them :slight_smile: