AngularJS:在Angular-rating-icons中添加工具提示吗?

时间:2019-05-12 04:08:51

标签: javascript html css angularjs

我正在使用angular-rating-icons生成恒星系统。

<div class="rating-filter">
    <h4>{{'Rating: '|translate}} {{filter.ratings}}</h4>
    <div data-angular-rating-icons 
    ng-model="filter.ratings" color-base="orange"
    on-change="fn()"></div>
</div>

我希望获得关于每颗星星的工具提示,类似于uib-tooltip中的实现方法。

<div class="btn-group">
    <button type="button" class="btn btn-price" uib-tooltip="₹0 - ₹500" ng-click="applyFilter(1)">$</button>
    <button type="button" class="btn btn-price" uib-tooltip="₹500 - ₹1000" ng-click="applyFilter(2)">$$</button>
    <button type="button" class="btn btn-price" uib-tooltip="₹1000 - ₹5000" ng-click="applyFilter(3)">$$$</button>
    <button type="button" class="btn btn-price" uib-tooltip="₹5000+" ng-click="applyFilter(4)">$$$$</button>
</div>

我似乎无法弄清楚这一点,因为angular-rating-icons接受String以确定哪个图标用于评级系统,即icon-full="fa-star"而不是传递{{1} }对象。而且我似乎无法针对单个恒星,因为它们被生成为最小CSS。

我尝试覆盖<div>的CSS,但这似乎也不是很好。有没有办法在每个按钮的悬停上显示工具提示?

JSFiddle:https://jsfiddle.net/y4b1skdw/1/

您可能必须将代码段的.fa-star击至Load Type才能加载插件。

1 个答案:

答案 0 :(得分:1)

:有没有办法在每个按钮的悬停上显示工具提示?

A :是-我们将工具提示类添加到<li ng-repeat="icon in icons track by $index"> ...,并且此<li>元素重复了10次,每颗星重复两次

以下是您的工具提示的代码段,并在CSS中添加了工具提示类

var app = angular.module("myApp", []);

app.directive('angularRating', function() {
  return {
    replace: true,
    require: 'ngModel',
    scope: {
      ngModel: '=',
      onChangeFunction: '&onChange'
    },
    template: '' +
      '<ul ng-class="[listClass, decimal]">' +
      '<li ng-repeat="icon in icons track by $index"  class="tooltip"' +
      'ng-style="getListItemStyle($index)" ' +
      'ng-click="setValue($index)" ' +
      'ng-mouseenter="paintIcons($index)" ' +
      'ng-mouseleave="resetIcons()" ' +
      '>' +
      '<span class="tooltiptext">sample Tooltip text for {{$index}}</span>' +
      '<i ng-class="getClass($index)" ng-style="getIconStyle($index)"></i>' +
      '</li>' +
      '</ul>',

    link: function(scope, element, attrs, controller) {
      // Settings
      scope.icons = new Array(+attrs.max || 5);
      scope.value = controller.$viewValue || (+attrs.defaultValue || 0);
      scope.size = +attrs.iconSize || 20;
      scope.spacing = +attrs.iconSpacing || 5;
      scope.listClass = 'angular-rating-icons';
      scope.readOnly = !(attrs.readonly === undefined);
      scope.decimal = !(attrs.decimal === undefined) ? 'angular-rating-icons-decimal' : undefined;

      // Colors
      var colorBase = attrs.colorBase || 'black';
      var colorSelected = attrs.colorSelected || 'orange';
      var colorHover = attrs.colorHover || 'orange';

      // Different states
      var iconBase = attrs.iconBase || 'fa';
      var iconEmpty = attrs.iconEmpty || 'fa-star-o';
      var iconFull = attrs.iconFull || 'fa-star';
      var iconHover = attrs.iconHover || 'fa-star';

      // Model
      controller.$render = function() {
        scope.value = controller.$viewValue === 0 ? 0 : controller.$viewValue || scope.value;

        // update model safeguard/fallback should it not be initialized before
        controller.$setViewValue(scope.value);
      };

      /**
       * Returns the appropriate class for the icon.
       * Changes if it's meant to be full or empty.
       * All indexes above the given value will be empty, all bellow or equal will be full.
       *
       * @param {int} index - the icon's index
       * @return {string} - the icon class to use
       */
      scope.getClass = function(index) {
        return iconBase + ' ' + (index >= scope.value ? iconEmpty : iconFull);
      };

      /**
       * Returns the appropriate style for the icon's color.
       * Changes if it's meant to be full or empty.
       * If it's decimal type, modifies the style to reduce the icon size by 2px, and move the odd index icons
       * half of their size minus 2, to the left.
       *
       * @param {int} index - the icon's index
       * @return {Object} - the icon style to use
       */
      scope.getIconStyle = function(index) {
        var css = {
          color: index >= scope.value ? colorBase : colorSelected
        };

        if (!scope.decimal) {
          return css;
        }

        css.height = scope.size - 2 + 'px';
        css.width = scope.size - 2 + 'px';
        css.left = index % 2 ? '-' + (scope.size - 2) / 2 + 'px' : '';

        return css;
      };

      /**
       * Returns the appropriate style fo the list item's font-size and padding-right.
       * If it's decimal type, modifies the style to reduce the height and width by 2 px, and the only the width
       * by half of that result. Also for every even index it removes the right padding.
       *
       * @param {int} index - the list item's index
       * @return {object} - the list item's style to use
       */
      scope.getListItemStyle = function(index) {
        var css = {
          'font-size': scope.size + 'px',
          'padding-right': index !== scope.icons.length - 1 ? scope.spacing + 'px' : '0'
        };

        if (!scope.decimal) {
          return css;
        }

        css.height = scope.size - 2 + 'px';
        css.width = (scope.size - 2) / 2 + 'px';

        if (!(index % 2)) {
          css['padding-right'] = '0';
        }

        return css;
      };

      /**
       * Doesn't run if set to readonly.
       * Sets the directive's scope value to the clicked icon plus 1.
       * List item's indexes go from 0 to 9, whilst real values should go from 1 to 10.
       * Sets the model's value to the directive's scope value.
       * Runs the onChangeFunction function.
       *
       * @param {int} index - the clicked icon's index
       */
      scope.setValue = function(index) {
        if (scope.readOnly) {
          return;
        }

        controller.$setViewValue(scope.value = index + 1);
        scope.onChangeFunction();
      };

      /**
       * Runs the paintIcon function to paint the icons only up to the current scope value - 1,
       * since the indexes range from 0 to 9 but the real values range from 1 to 10.
       */
      scope.resetIcons = function() {
        scope.paintIcons(scope.value - 1, true);
      };

      /**
       * Doesn't run if set to readonly.
       * Changes the icon's classes accordingly to their index.
       * Cycles all the icons, and if the current index is smaller than the cycle number, it gives the icon the
       * empty class, otherwise gives it the hover class and sets the color to the hover color.
       * If reset is true, the above first case scenario also sets the color to the base color, and the second
       * adds the class full and paints with the selected color instead.
       *
       * @param {int} index - the clicked icon's index
       * @param {boolean} reset - if icon's paint should be reset
       */
      scope.paintIcons = function(index, reset) {
        if (scope.readOnly) {
          return;
        }

        var items = element.find('li').find('i');
        for (var i = 0; i < items.length; i++) {
          var icon = angular.element(items[i]);

          if (index >= i) {
            icon.removeClass(iconEmpty)
              .addClass(reset ? iconFull : iconHover)
              .css('color', reset ? colorSelected : colorHover);
          } else {
            icon.removeClass(iconFull)
              .addClass(iconEmpty)
              .css('color', reset ? colorBase : icon.css('color'));
          }

          if (reset && iconHover !== iconFull) {
            icon.removeClass(iconHover);
          }
        }
      };
    }
  };
});

app.controller("MyCtrl", ['$scope', function($scope) {
  $scope.maxValue = 10;

  $scope.fn = function() {
    if ($scope.rating.value === 10) {
      $scope.callbackText = 'This text was changed through the callback function! ' +
        'And it was validated to say "YOU\'RE AWESOME" ' +
        'if the value was 10!';
      return;
    }
    $scope.callbackText = 'The new rating is ' + $scope.rating.value + '. ' +
      'This text was changed through a callback function! ' +
      'Try hitting the max value star!';
  }
}]);
.angular-rating-icons {
  text-align: left;
  display: inline-block;
  padding: 0;
  list-style: none;
}

.angular-rating-icons>li {
  display: inline-block;
  padding: 0;
  cursor: pointer;
}

.angular-rating-icons-decimal>li {
  overflow: hidden;
  position: relative;
}

.angular-rating-icons-decimal>li>i {
  position: absolute;
}

.tooltip {
  position: relative;
  display: inline-block;
  border-bottom: 1px dotted black;
}

.tooltip .tooltiptext {
  visibility: hidden;
  width: 120px;
  background-color: black;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px 0;
  /* Position the tooltip */
  position: fixed;
  font-size: 14px;
  margin-top: 45px;
  z-index: 1;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://use.fontawesome.com/2bd9c462bc.js"></script>

<div ng-app="myApp">
  <div ng-controller="MyCtrl">
    <h3>Hello, Superhero!</h3>

    <div>Rating: {{rating.value}}</div>

    <div data-angular-rating ng-model='rating.value' max={{maxValue}} default-value=2 icon-empty="fa-star-o" icon-full="fa-star" icon-hover="fa-star" color-base="black" color-selected="orange" color-hover="orange" icon-size="50" on-change="fn()" decimal></div>

    <div>{{callbackText}}</div>
  </div>
</div>