var app = angular.module('plunker', ['at.multirange-slider']);

app.controller('MainCtrl', function($scope, $sce) {

  $scope.addItem = function() {
    $scope.probs.push({
      p: Math.random(),
      symbol: $sce.trustAsHtml($scope.probs.length + ' ♠')
    });
  }
  $scope.removeItem = function() {
    $scope.probs.pop();
  }
  $scope.probs = [{
    p: 0.1,
    symbol: $sce.trustAsHtml('3 ♥')
  }, {
    p: 0.5,
    symbol: $sce.trustAsHtml('4 ♠')
  }, {
    p: 0.4,
    symbol: $sce.trustAsHtml('7 ♣')
  }];
  $scope.otherProbs = {
    key1: {
      p: 3
    },
    key2: {
      p: 5
    },
    key4: {
      p: 6
    }
  };


});
<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS responsive multi-range slider - CodePen</title>
  <link rel="stylesheet" href="style.css" />
  <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8"></script>
  <script src="multirange-slider.js"></script>
  <link rel="stylesheet" href="multirange-slider.css" media="screen" type="text/css" />
  <script src="app.js"></script>
  <style>
    .slider {
      background: #022;
    }
  </style>
</head>

<body ng-controller="MainCtrl">

  <h3>AngularJS Responsive Multi-range slider</h3>
  <div>
    <div style="width: 50%;">

      <h4>Here's one with a map.</h4>
      <slider>
        <slider-range model="val.p" ng-repeat="(key,val) in otherProbs">
          <div class="slider-handle">&larr;&rarr;</div>
        </slider-range>
      </slider>
      <input type='text' ng-model='val.p' ng-repeat='(key, val) in otherProbs'>
      <p>
        model: {{otherProbs}}
      </p>

      <h4>Here's one with an array of objects, a step size, and some playing cards.</h4>
      <button ng-click="addItem(otherProbs)">Add Item</button>
      <button ng-click="removeItem(otherProbs)">Remove Item</button>
      <slider step=".05">
        <slider-range model="val.p" ng-repeat="val in probs">
          <div class="slider-handle" ng-bind-html="val.symbol"></div>
          <div class="slider-label">{{val.p | number:2 }}</div>
        </slider-range>
      </slider>
      <input type='text' ng-model='val.p' ng-repeat='val in probs'>
      <p>
        model: {{probs}}
        <br>property: "p"
        <br>step: .05
      </p>
    </div>
    <br>

  </div>
</body>

</html>

.at-multirange-slider {
  height: 1em;
  padding-top: .5em;
}

.at-multirange-slider .slider {
  height: 2px;
}

.at-multirange-slider .slider-range {
  
  box-sizing: border-box;
  display: inline-block;
  
  vertical-align: top;
  height: 2px;
}

.at-multirange-slider .slider-handle {
  z-index: 100;
  margin-top: -.5em;
  height: 1em;
  border: 1px solid #133;
  border-radius: 2px;
  background: #fff;
  cursor: pointer;
}

.at-multirange-slider .slider-handle:hover {
  background: #ddd;
}

.at-multirange-slider .slider-range:last-child .slider-handle{
    display: none;
}

.at-multirange-slider .slider-label {
  text-align: center;
  padding-top: .25em;
  font-size: .75em;
}
Status API Training Shop Blog About Pricing
© 2015 GitHub, Inc. Terms P
var sliderDirective, sliderHandleDirective, sliderRangeDirective;

angular.module('at.multirange-slider', []);

sliderDirective = function($parse, $compile) {
  var sliderController;
  sliderController = function($scope, $element, $attrs) {
    var get;
    this.ranges = [];
    this.handles = [];
    this.pTotal = function() {
      return this.ranges.reduce((function(sum, range) {
        return sum + range.value();
      }), 0);
    };
    this.step = ($attrs.step != null) ? (get = $parse($attrs.step), function() {
      return parseFloat(get());
    }) : function() {
      return 0;
    };
    this._width = 0;
    this.updateRangeWidths = function() {
      var handle, i, j, len, len1, pRunningTotal, range, ref, ref1, results, total;
      this._width = $element.prop('clientWidth');
      pRunningTotal = 0;
      total = this.pTotal();
      ref = this.ranges;
      for (i = 0, len = ref.length; i < len; i++) {
        range = ref[i];
        pRunningTotal += range.value();
        range.update(pRunningTotal, total);
      }
      ref1 = this.handles;
      results = [];
      for (j = 0, len1 = ref1.length; j < len1; j++) {
        handle = ref1[j];
        results.push(handle.updateWidth());
      }
      return results;
    };
    this.elementWidth = function() {
      return this._width - this.handles.reduce(function(sum, handle) {
        return sum + handle.width();
      }, 0);
    };
    return this;
  };
  sliderController.$inject = ['$scope', '$element', '$attrs'];
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    template: "<div class=\"at-multirange-slider\">\n  <div class=\"slider\" ng-transclude>\n  </div>\n</div>",
    link: function(scope, element, attrs, ctrl) {
      return element.children().css('position', 'relative');
    },
    controller: sliderController
  };
};

sliderRangeDirective = function($parse) {
  var sliderRangeController;
  sliderRangeController = function($scope) {
    return {};
  };
  sliderRangeController.$inject = ["$scope"];
  return {
    template: "<div class=\"slider-range\" ng-transclude>\n</div>",
    require: ['^slider', 'sliderRange'],
    restrict: 'E',
    replace: true,
    transclude: true,
    controller: sliderRangeController,
    compile: function() {
      return {
        pre: function(scope, element, attrs, arg) {
          var range, slider, valueFn;
          slider = arg[0], range = arg[1];
          valueFn = $parse(attrs.model);
          slider.ranges.push(range);
          scope.$watch(attrs.model, (function() {
            return slider.updateRangeWidths();
          }));
          return angular.extend(range, {
            widthAdjustment: '0px',
            value: function(_) {
              var s;
              if (_ == null) {
                return parseFloat('' + valueFn(scope, {}), 10);
              }
              s = slider.step();
              if (s > 0) {
                _ = Math.round(_ / s) * s;
              }
              return valueFn.assign(scope, _);
            },
            update: function(runningTotal, total) {
              var rangeWidth, x;
              x = runningTotal / total * 100;
              rangeWidth = this.value() / total * 99.9;
              return element.css({
                width: rangeWidth * slider.elementWidth() / 100 > 1 ? "calc(" + rangeWidth + "% - " + this.widthAdjustment + ")" : '0',
                'margin-left': this.widthAdjustment
              });
            },
            adjustWidth: function(margin) {
              return this.widthAdjustment = margin;
            }
          });
        },
        post: function(scope, element, attrs, arg) {
          var range, slider;
          slider = arg[0], range = arg[1];
          return element.on('$destroy', function() {
            slider.ranges.splice(slider.ranges.indexOf(range), 1);
            return slider.updateRangeWidths();
          });
        }
      };
    }
  };
};

sliderHandleDirective = function($document) {
  return {
    replace: false,
    restrict: 'AC',
    require: ['^slider', '^sliderRange'],
    link: function(scope, element, attrs, arg, transclude) {
      var handle, nextRange, range, slider, startPleft, startPright, startX;
      slider = arg[0], range = arg[1];
      nextRange = function() {
        return slider.ranges[slider.ranges.indexOf(range) + 1];
      };
      slider.handles.push(handle = {
        _width: 0,
        width: function() {
          return this._width;
        },
        updateWidth: function() {
          var ref;
          this._width = element.prop('clientWidth');
          element.css({
            float: 'right',
            marginRight: -handle.width() / 2 + 'px'
          });
          return (ref = nextRange()) != null ? ref.adjustWidth(handle.width() / 2 + 'px') : void 0;
        }
      });
      startX = 0;
      startPleft = startPright = 0;
      return element.on('mousedown', function(event) {
        var mousemove, mouseup, ref;
        if (nextRange() == null) {
          return;
        }
        mousemove = function(event) {
          return scope.$apply(function() {
            var dp, ref;
            dp = (event.screenX - startX) / slider.elementWidth() * slider.pTotal();
            if (dp < -startPleft || dp > startPright) {
              return;
            }
            range.value(startPleft + dp);
            if ((ref = nextRange()) != null) {
              ref.value(startPright - dp);
            }
            return slider.updateRangeWidths();
          });
        };
        mouseup = function() {
          $document.unbind('mousemove', mousemove);
          return $document.unbind('mouseup', mouseup);
        };
        event.preventDefault();
        startX = event.screenX;
        startPleft = range.value();
        startPright = (ref = nextRange()) != null ? ref.value() : void 0;
        $document.on('mousemove', mousemove);
        return $document.on('mouseup', mouseup);
      });
    }
  };
};

sliderDirective.$inject = ['$parse', '$compile'];

sliderRangeDirective.$inject = ['$parse'];

sliderHandleDirective.$inject = ['$document'];

angular.module('at.multirange-slider').directive('slider', sliderDirective).directive('sliderRange', sliderRangeDirective).directive('sliderHandle', sliderHandleDirective);