如何根据响应动态显示星级?

时间:2016-08-08 07:39:33

标签: angularjs

我需要根据回复动态显示星级。

我可以显示1到5的值,但如果等级为0,则不会显示空星。

如果评级= 0.4,它也会显示1颗星。

我的控制器:

(function() {
    'use strict';


    angular
    var app = angular
        .module('app')

 app.directive('starRating', function () {

    return {
        restrict: 'A',
        template: '<ul class="rating">' +
            '<li ng-repeat="star in stars" ng-class="star" ng-click="toggle($index)">' +
            '\u2605' +
            '</li>' +
            '</ul>',
        scope: {
            ratingValue: '=',
            max: '='
        },
        link: function (scope, elem, attrs) {

            var updateStars = function () {

                scope.stars = [];
                for (var i = 0; i < scope.max; i++) {
                    if(i == 0) {
                        scope.stars = [];
                        scope.stars.push({
                        empty: i = 0
                    });
                    } else {
                    scope.stars.push({
                        filled: i < scope.ratingValue
                    });
                    }
                }

            };
            scope.$watch('ratingValue', function (oldVal, newVal) {
                if (newVal) {
                    updateStars();
                }
            });
        }
    }
});


app.controller('Controller', Controller);

    Controller.$inject = ['UserService', '$location', '$rootScope', '$scope', 'fileUpload', 'FlashService', '$cookieStore', '$timeout', '$window'];

    function Controller(UserService, $location, $rootScope, $scope, fileUpload, FlashService, $cookieStore, $timeout, $window) {

$scope.selectTestSubject = function() {

$scope.rating = 0;

    console.log(levels.length);   

        for(var k=0; k<levels.length; k++) { 
           var respRating = levels[k].rating;
//           var respRating = 1.5;

            console.log(respRating);

            $scope.ratings = [{
                current: respRating,
                max: 5
            }];

            if(respRating == 0) {

                $scope.defaultRating = true;
            } else {

                $scope.defaultRating = false;
            }
         }
     }
  }
}) ();

我的HTML页面:

<div><span ng-repeat="rating in ratings">

        <div star-rating rating-value="rating.current" max="rating.max"></div>
        </span>
    </div>

1 个答案:

答案 0 :(得分:2)

您的解决方案的一个问题是您的$ watch表达式。你有以下地方:

scope.$watch('ratingValue', function (oldVal, newVal) {
    if (newVal) {
        updateStars();
    }
});

oldValnewVal实际上是错误的方式,$ watch函数首先接受新值后跟旧值。其次,条件if (newVal)对0不起作用,因为0是假值。

相反,你应该:

scope.$watch('ratingValue', function(value, previousValue) {
    // Only update the view when the value has changed.
    if (value !== previousValue) {
        updateStars();
    }
});

您的updateStars函数也始终重新初始化scope.stars变量并附加到其上。这样做可能会产生一些不必要的副作用,导致视图无法反映模型值。最好初始化数组,然后附加项目(如果它尚不存在)或更新现有值。所以你会有这样的事情:

// Initialise the stars array.
scope.stars = [];

var updateStars = function() {

    for (var i = 0; i < scope.max; i++) {
        var filled = i < Math.round(scope.ratingValue);
        // Check if the item in the stars array exists and 
        // append it, otherwise update it.
        if (scope.stars[i] === undefined) {
            scope.stars.push({
                filled: filled
            });
        } else {
            scope.stars[i].filled = filled;
        }
    }

};

由于$ watch表达式仅在值更改时更新星标,因此您现在需要在链接功能首次触发时触发更新。所以这很简单:

// Trigger an update immediately.
updateStars();

您的模板也未正确使用星标上的filled属性,而应包含相应的ng-class,如下所示:

<ul class="rating">
    <li class="star" 
        ng-repeat="star in stars" 
        ng-class="{ filled: star.filled }"
        ng-click="toggle($index)">
      \u2605
    </li>
</ul>

用简单的风格

.star {
  cursor: pointer;
  color: black;
}

.star.filled {
  color: yellow;
}

您还可以通过聆听mouseentermouseleave效果来改善此评级系统,以便在用户选择新值时星号显示为黄色。这是非常常见的功能。您可以通过一些修改来实现这一目标。

首先,应该更新模板以监听这些事件:

<ul class="rating">
    <li class="star" 
        ng-repeat="star in stars" 
        ng-class="{ filled: star.filled }"
        ng-mouseenter="onMouseEnter($event, $index + 1)"
        ng-mouseleave="onMouseLeave($event)"
        ng-click="toggle($index)">
      \u2605
    </li>
</ul>

接下来,我们想对updateStars函数进行一些小调整,以获取一个评级参数:

var updateStars = function(rating /* instead of blank */ ) {

    for (var i = 0; i < scope.max; i++) {
        var filled = i < Math.round(rating); // instead of scope.ratingValue
        // Check if the item in the stars array exists and 
        // append it, otherwise update it.
        if (scope.stars[i] === undefined) {
            scope.stars.push({
                filled: filled
            });
        } else {
            scope.stars[i].filled = filled;
        }
    }

};

// Trigger an update immediately.
updateStars(scope.ratingValue /* instead of blank */ );

scope.$watch('ratingValue', function(value, previousValue) {
    // Only update the view when the value changed.
    if (value !== previousValue) {
        updateStars(scope.ratingValue /* instead of blank */ );
    }
});

现在我们可以从视图

添加我们的事件回调
// Triggered when the cursor enters a star rating (li element).
scope.onMouseEnter = function (event, rating) {
    updateStars(rating);
};

// Triggered when the cursor leaves a star rating.
scope.onMouseLeave = function (event) {
    updateStars(scope.ratingValue);
};

就是这样! Full demo here.