3

Here is a code which present star rating code in angularjs. In some point I need to have a average of all the rating in whole the system so instead of rate:2 , i will have 2.4 . In such case i am interesting to present 2 star which are complete fill and one which has only half filled. How can I change my code in order to add this functionality? Moreover, initially I would like to don't specify any star filled. That's also need a modification which I am not sure how should be done?

<div ng-app="app" ng-controller="RatingCtrl" class="container">
  <h1>Angular Star Rating Directive</h1>
  <div star-rating ng-model="rating1" max="10" on-rating-selected="rateFunction(rating)"></div>
  <star-rating ng-model="rating2" readonly="isReadonly"></star-rating>
  <label>
    <input type="checkbox" ng-model="isReadonly" /> Is Readonly
  </label>

  <div><strong>Rating 1:</strong> {{rating1}}</div>
  <div><strong>Rating 2:</strong> {{rating2}}</div>
</div>

In my directive

angular.module("app", [])
.controller("RatingCtrl", function($scope) {
  $scope.rating1 = 1;
  $scope.rating2 = 2;
  $scope.isReadonly = true;
  $scope.rateFunction = function(rating) {
    console.log("Rating selected: " + rating);
  };
})
.directive("starRating", function() {
  return {
    restrict : "EA",
    template : "<ul class='rating' ng-class='{readonly: readonly}'>" +
               "  <li ng-repeat='star in stars' ng-class='star' ng-click='toggle($index)'>" +
               "    <i class='fa fa-star'></i>" + //&#9733
               "  </li>" +
               "</ul>",
    scope : {
      ratingValue : "=ngModel",
      max : "=?", //optional: default is 5
      onRatingSelected : "&?",
      readonly: "=?"
    },
    link : function(scope, elem, attrs) {
      if (scope.max == undefined) { scope.max = 5; }
      function updateStars() {
        scope.stars = [];
        for (var i = 0; i < scope.max; i++) {
          scope.stars.push({
            filled : i < scope.ratingValue
          });
        }
      };
      scope.toggle = function(index) {
        if (scope.readonly == undefined || scope.readonly == false){
          scope.ratingValue = index + 1;
          scope.onRatingSelected({
            rating: index + 1
          });
        }
      };
      scope.$watch("ratingValue", function(oldVal, newVal) {
        if (newVal) { updateStars(); }
      });
    }
  };
});

and css

.rating {
  margin: 0;
  padding: 0;
  display: inline-block;
}
.rating li {
  padding: 1px;
  color: #ddd;
  font-size: 20px;
  text-shadow: .05em .05em #aaa;
  list-style-type: none;
  display: inline-block;
  cursor: pointer;
}
.rating li.filled {
  color: #fd0;
}
.rating.readonly li.filled {
  color: #666;
}

http://codepen.io/anon/pen/RPLJYW

Thank you for any help.

pm1359
  • 622
  • 1
  • 10
  • 31
  • The following link can be helpful: [http://stackoverflow.com/questions/23646395/rendering-a-star-rating-system-using-angularjs/39367524#39367524][1] – Arun Saini Mar 07 '17 at 07:52

2 Answers2

5

You could use two identical set of stars to achieve this, position absolute one on top of the other. One fills your background star shapes (gray) and the one position at the top will represent your fill.

The top set of stars are all filled but its container's width can be adjusted to the proportion of stars representing your rate.

var score = 2.4;
var maxStars = 5;
var starContainerMaxWidth = 100; //pixls
var filledInStarsContainerWidth = score / maxStars * starsMaxWidth;

A CSS overflow hidden will hide the portion of stars that are not turned on, in effect allowing you to show 2.4 stars filled.

Update:

I have bashed a quick example http://codepen.io/anon/pen/NqazVa , will need some tidy up and reshuffling but the average rate is calculated and displayed correctly.

Giuseppe Romagnuolo
  • 3,362
  • 2
  • 30
  • 38
3

Check the AngularUI Bootstrap Rating component.

http://angular-ui.github.io/bootstrap/#/rating

Onur Gazioğlu
  • 501
  • 2
  • 12