0

I am using http://danielcrisp.github.io/angular-rangeslider/demo/ to create a range slider but I would like it to use time(HH:MM) not just plain numbers. So it would range from 10m - 2hr. However I am a bit confused about how to achieve this.

Would I be better off formatting the time like this:

$scope.minTime = 10;
$scope.maxTime = 120;

The time is calculated in minutes then perhaps I could somehow maybe using the date filter convert the numbers into hh:mm but I would still prefer if it were formatted something like (10min, 30min, 1hr, 1hr 10min, 1hr 30min, 2hr)

Or is this a better way to do it:

$scope.minTime = 00:10;
$scope.maxTime = 02:00;

Or have I completely missed this and there is a better way?

Daimz
  • 3,243
  • 14
  • 49
  • 76
  • Probably the former rather than the latter, since I can't imagine a *range* slider would allow you to use string values. If the plugin allows you to use custom filters for the UI output, then you can write your own to output to 10min, 1hr 30min, etc. – Marc Kline May 18 '14 at 15:11

1 Answers1

3

The best options seems to be storing the values as minutes and displaying them using a custom filter.

<div ng-controller="myCtrl">
    <div range-slider pin-handle="min" attach-handle-values
         prevent-equal-min-max step="{{sliderConfig.step}}"
         min="sliderConfig.min" max="sliderConfig.max"
         model-min="sliderConfig.userMin" model-max="sliderConfig.userMax" 
         filter="hourMinFilter">
    </div>
</div>

app.controller('myCtrl', function ($scope) {
    $scope.sliderConfig = {
        min:  0,
        max:  120,
        step: 10,
        userMin: 0,
        userMax: 30
    };
});

app.filter('hourMinFilter', function () {
    return function (value) {
        var h = parseInt(value / 60);
        var m = parseInt(value % 60);

        var hStr = (h > 0) ? h + 'hr'  : '';
        var mStr = (m > 0) ? m + 'min' : '';
        var glue = (hStr && mStr) ? ' ' : '';

        return hStr + glue + mStr;
    };
});

See, also, this short demo.


UPDATE:

A modified version to allow a customizable filter max-value and show a different literal (by popular demand):

1) Extend the filter to receive a second argument: the max limit.

...
return function (value, max) {
    if (value == max) { return 'All'; }

    var h = parseInt(value / 60);
    var m = parseInt(value % 60);
    ...

Note: The use of == instead of === is very important in order to check a string representation of the number against an actual number. If you want to avoid using ==, you should first convert both arguments to either String or Integer.

2) Modify the HTML to include the extra filter argument:

<div range-slider pin-handle="min" attach-handle-values
     ....
     filter="hourMinFilter" filter-options="{{sliderConfig.max}}">
</div>

See, also, this updated demo.

gkalpak
  • 47,844
  • 8
  • 105
  • 118
  • Thats Perfect! May I ask what does the `%` mean in the `var m = parseInt(value % 60);` I understand everything else but one confused me. Thanks for the help. – Daimz May 18 '14 at 23:26
  • One last thing. If I wanted to add an 'all' or '2hr +' to the last max value how might could I do this? – Daimz May 18 '14 at 23:44
  • Look up `%` in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators – Marc Kline May 19 '14 at 02:36
  • This is a mod of the Fiddler with a max "All" value: http://jsfiddle.net/marcolepsy/66D39/ – Marc Kline May 19 '14 at 02:43
  • How could I use the sliders actual max value instead of a number like '130'? This would make the filter more versatile. – Daimz May 19 '14 at 04:28
  • Also I had a look at that documentation for `%` thank you. However it didn't make sense to me. How does 12 % 5 = 2? 12 - (5*2) = 2 I can get that but their example left me confused. – Daimz May 19 '14 at 06:27
  • @Daimz: I am not sure what you mean by _"the sliders actual max value"_. BTW, in case you are still wondering about the `%`: It returns the modulo from dividing `value` with `60` (the number of minutes in an hour). The first expression (`parseInt(value / 60)`) returns the number of hours (integral part of the division of `value` with `60`) and the second expression (`value % 60`) returns the remainder of that division, i.e. the number of minutes that remain and do not add up to a full hour. – gkalpak May 19 '14 at 10:51
  • @ExpertSystem that makes more sence, thanks for the explanation. What I meant by the 'sliders actual max value' is, in @Marc Kline's fiddle http://jsfiddle.net/marcolepsy/66D39/ he has `if (value === 130) return 'All'` so that when the slider is at '130' to shows 'all' instead of the numbers '130'. But in `$scope.sliderConfig` I have `max` I would like to use this value instead of '130' that way if I apply the filter to multiple range sliders each one can have a different 'max' and the filter would be able to handle this, so if one max was 130 the other 270 then it would say all at 130 & 270 – Daimz May 19 '14 at 11:09
  • I hardcoded the `130` value in, which will not work that value doesn't work in all of your use cases. In that case, your solution would have to be more sophisticated, so I might suggest either opening a new question or contacting me. The comments here are getting a bit long in the tooth. – Marc Kline May 19 '14 at 13:01
  • Ah this actually answers a queastion I have had for a while now, `return function (value, max) { if (value == max) { return 'All'; }` So when I make a filter I can access a variable in the controller that the filter is used in by including that variable in the function `function (value, max)` Is that right? Thanks alot by the way that appears to work perfectly. – Daimz May 20 '14 at 09:40
  • @Daimz: You can pass any number of arguments (either hard-coded or bound to scope properties) separated by `:`. E.g. `{{someValue | myFilter:arg1:'arg2':argN}}` -> `.filter('myFilter', function () { return function (a1, a2, a3, a4) {}; });`, where `a1 -> $scope.someValue`, `a2 -> $scope.arg1`, `a3 = 'arg2'`, `a4 -> $scope.argN` – gkalpak May 20 '14 at 09:50
  • Would it be possible to have 2 buttons to specify a range within the slider? –  Jun 21 '14 at 13:11
  • @iwayneo: I don't really get the question and I don't see how it is related to this one. But I suspect the answer is yes :) – gkalpak Jun 21 '14 at 13:36
  • So - is it possible to have 2 sliders in one like this one: http://prajwalkman.github.io/angular-slider/ except for time ranges? –  Jun 21 '14 at 14:46
  • As in - given a 24 hour timespan I want to select a start and an end within that 24 hours –  Jun 21 '14 at 14:47
  • @iwayneo: I don't see why wouldn't it be possible. Seems like all you need to do is remove the `pin-handle` attribute. What have you tried ? Did you face any problems ? – gkalpak Jun 21 '14 at 14:56