Skip to content

Commit 53c56e5

Browse files
Valentin HervieuValentin Hervieu
Valentin Hervieu
authored and
Valentin Hervieu
committed
feat(range): Add a noSwitching value to prevent switching min/max
1 parent b5960c2 commit 53c56e5

File tree

11 files changed

+398
-189
lines changed

11 files changed

+398
-189
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 2.6.0 (not-released)
2+
## Features
3+
- Add a `noSwitching` option to prevent the user from switching the min and max handles (#233).
4+
15
# 2.5.0 (2016-01-24)
26
## Features
37
- Add a `minRange` option to set a minimal range (#231).

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ The default options are:
178178
keyboardSupport: true,
179179
scale: 1,
180180
enforceRange: false,
181+
noSwitching: false,
181182
onlyBindHandles: false,
182183
onStart: null,
183184
onChange: null,
@@ -193,7 +194,7 @@ The default options are:
193194

194195
**precision** - _Number (defaults to 0)_: The precision to display values with. The `toFixed()` is used internally for this.
195196

196-
**minRange** - _Number (defaults to 0)_: The minimum range authorized on the slider.
197+
**minRange** - _Number (defaults to 0)_: The minimum range authorized on the slider. *Applies to range slider only.*
197198

198199
**translate** - _Function(value, sliderId)_: Custom translate function. Use this if you want to translate values displayed on the slider. For example if you want to display dollar amounts instead of just numbers:
199200
```html
@@ -220,9 +221,9 @@ $scope.slider = {
220221

221222
**stepsArray** - _Array_: If you want to display a slider with non linear/number steps. Just pass an array with each slider value and that's it; the floor, ceil and step settings of the slider will be computed automatically. The `rz-slider-model` value will be the index of the selected item in the stepsArray.
222223

223-
**draggableRange** - _Boolean (defaults to false)_: When set to true and using a range slider, the range can be dragged by the selection bar.
224+
**draggableRange** - _Boolean (defaults to false)_: When set to true and using a range slider, the range can be dragged by the selection bar. *Applies to range slider only.*
224225

225-
**draggableRangeOnly** - _Boolean (defaults to false)_: Same as draggableRange but the slider range can't be changed.
226+
**draggableRangeOnly** - _Boolean (defaults to false)_: Same as draggableRange but the slider range can't be changed. *Applies to range slider only.*
226227

227228
**showSelectionBar** - _Boolean (defaults to false)_: Set to true to always show the selection bar before the slider handle.
228229

@@ -250,6 +251,8 @@ $scope.slider = {
250251

251252
**enforceRange** - _Boolean (defaults to false)_: Set to true to round the `rzSliderModel` and `rzSliderHigh` to the slider range even when modified from outside the slider. When set to false, if the model values are modified from outside the slider, they are not rounded but they are still rendered properly on the slider.
252253

254+
**noSwitching** - _Boolean (defaults to false)_: Set to true to prevent to user from switching the min and max handles. *Applies to range slider only.*
255+
253256
**onlyBindHandles** - _Boolean (defaults to false)_: Set to true to only bind events on slider handles.
254257

255258
**onStart** - _Function(sliderId, modelValue, highValue)_: Function to be called when a slider update is started. If an id was set in the options, then it's passed to this callback. This callback is called before any update on the model.

demo/demo.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ app.controller('MainCtrl', function($scope, $rootScope, $timeout, $modal) {
2929
}
3030
};
3131

32+
//Range slider with noSwitching config
33+
$scope.noSwitchingSlider = {
34+
minValue: 10,
35+
maxValue: 90,
36+
options: {
37+
floor: 0,
38+
ceil: 100,
39+
step: 1,
40+
noSwitching: true
41+
}
42+
};
43+
3244
//Slider with selection bar
3345
$scope.slider_visible_bar = {
3446
value: 10,

demo/index.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ <h2>Range slider with minimum range of 10</h2>
4545
></rzslider>
4646
</article>
4747

48+
<article>
49+
<h2>Range slider with noSwitching=true</h2>
50+
<rzslider
51+
rz-slider-model="noSwitchingSlider.minValue"
52+
rz-slider-high="noSwitchingSlider.maxValue"
53+
rz-slider-options="noSwitchingSlider.options"
54+
></rzslider>
55+
</article>
56+
4857
<article>
4958
<h2>Slider with visible selection bar</h2>
5059
<rzslider

dist/rzslider.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ rzslider .rz-pointer:hover:after {
9898
background-color: #ffffff;
9999
}
100100

101+
rzslider .rz-pointer.rz-active {
102+
z-index: 4;
103+
}
104+
101105
rzslider .rz-pointer.rz-active:after {
102106
background-color: #451aff;
103107
}

dist/rzslider.js

Lines changed: 55 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*! angularjs-slider - v2.5.0 -
22
(c) Rafal Zajac <rzajac@gmail.com>, Valentin Hervieu <valentin@hervieu.me>, Jussi Saarivirta <jusasi@gmail.com>, Angelin Sirbu <angelin.sirbu@gmail.com> -
33
https://github.com/angular-slider/angularjs-slider -
4-
2016-01-24 */
4+
2016-01-25 */
55
/*jslint unparam: true */
66
/*global angular: false, console: false, define, module */
77
(function(root, factory) {
@@ -52,6 +52,7 @@
5252
keyboardSupport: true,
5353
scale: 1,
5454
enforceRange: false,
55+
noSwitching: false,
5556
onlyBindHandles: false,
5657
onStart: null,
5758
onChange: null,
@@ -798,7 +799,7 @@
798799
callOnStart: function() {
799800
if (this.options.onStart) {
800801
var self = this;
801-
this.scope.$evalAsync(function () {
802+
this.scope.$evalAsync(function() {
802803
self.options.onStart(self.options.id, self.scope.rzSliderModel, self.scope.rzSliderHigh);
803804
});
804805
}
@@ -813,7 +814,7 @@
813814
callOnChange: function() {
814815
if (this.options.onChange) {
815816
var self = this;
816-
this.scope.$evalAsync(function () {
817+
this.scope.$evalAsync(function() {
817818
self.options.onChange(self.options.id, self.scope.rzSliderModel, self.scope.rzSliderHigh);
818819
});
819820
}
@@ -828,7 +829,7 @@
828829
callOnEnd: function() {
829830
if (this.options.onEnd) {
830831
var self = this;
831-
this.scope.$evalAsync(function () {
832+
this.scope.$evalAsync(function() {
832833
self.options.onEnd(self.options.id, self.scope.rzSliderModel, self.scope.rzSliderHigh);
833834
});
834835
}
@@ -843,7 +844,7 @@
843844
updateHandles: function(which, newOffset) {
844845
if (which === 'rzSliderModel')
845846
this.updateLowHandle(newOffset);
846-
else if (which === 'rzSliderHigh')
847+
else
847848
this.updateHighHandle(newOffset);
848849

849850
this.updateSelectionBar();
@@ -883,7 +884,7 @@
883884
},
884885

885886
/**
886-
* Show / hide floor / ceiling label
887+
* Show/hide floor/ceiling label
887888
*
888889
* @returns {undefined}
889890
*/
@@ -1177,8 +1178,15 @@
11771178
if (!this.range) {
11781179
return this.minH;
11791180
}
1180-
var offset = this.getEventPosition(event);
1181-
return Math.abs(offset - this.minH.rzsp) < Math.abs(offset - this.maxH.rzsp) ? this.minH : this.maxH;
1181+
var offset = this.getEventPosition(event),
1182+
distanceMin = Math.abs(offset - this.minH.rzsp),
1183+
distanceMax = Math.abs(offset - this.maxH.rzsp);
1184+
if (distanceMin < distanceMax)
1185+
return this.minH;
1186+
else if (distanceMin > distanceMax)
1187+
return this.maxH;
1188+
else
1189+
return offset < this.maxPos / 2 ? this.minH : this.maxH;
11821190
},
11831191

11841192
/**
@@ -1322,21 +1330,14 @@
13221330
newValue;
13231331

13241332
if (newOffset <= 0) {
1325-
if (pointer.rzsp === 0)
1326-
return;
13271333
newValue = this.minValue;
1328-
newOffset = 0;
13291334
} else if (newOffset >= this.maxPos) {
1330-
if (pointer.rzsp === this.maxPos)
1331-
return;
13321335
newValue = this.maxValue;
1333-
newOffset = this.maxPos;
13341336
} else {
13351337
newValue = this.offsetToValue(newOffset);
13361338
newValue = this.roundStep(newValue);
1337-
newOffset = this.valueToOffset(newValue);
13381339
}
1339-
this.positionTrackingHandle(newValue, newOffset);
1340+
this.positionTrackingHandle(newValue);
13401341
},
13411342

13421343
/**
@@ -1402,36 +1403,28 @@
14021403
if (action == null || this.tracking === '') return;
14031404
event.preventDefault();
14041405

1405-
var newValue = this.roundStep(this.sanitizeValue(action)),
1406-
newOffset = this.valueToOffset(newValue);
1406+
var newValue = this.roundStep(this.sanitizeValue(action));
14071407
if (!this.options.draggableRangeOnly) {
1408-
this.positionTrackingHandle(newValue, newOffset);
1408+
this.positionTrackingHandle(newValue);
14091409
} else {
14101410
var difference = this.scope.rzSliderHigh - this.scope.rzSliderModel,
1411-
newMinOffset, newMaxOffset,
14121411
newMinValue, newMaxValue;
14131412
if (this.tracking === 'rzSliderModel') {
14141413
newMinValue = newValue;
1415-
newMinOffset = newOffset;
14161414
newMaxValue = newValue + difference;
14171415
if (newMaxValue > this.maxValue) {
14181416
newMaxValue = this.maxValue;
14191417
newMinValue = newMaxValue - difference;
1420-
newMinOffset = this.valueToOffset(newMinValue);
14211418
}
1422-
newMaxOffset = this.valueToOffset(newMaxValue);
14231419
} else {
14241420
newMaxValue = newValue;
1425-
newMaxOffset = newOffset;
14261421
newMinValue = newValue - difference;
14271422
if (newMinValue < this.minValue) {
14281423
newMinValue = this.minValue;
14291424
newMaxValue = newMinValue + difference;
1430-
newMaxOffset = this.valueToOffset(newMaxValue);
14311425
}
1432-
newMinOffset = this.valueToOffset(newMinValue);
14331426
}
1434-
this.positionTrackingBar(newMinValue, newMaxValue, newMinOffset, newMaxOffset);
1427+
this.positionTrackingBar(newMinValue, newMaxValue);
14351428
}
14361429
},
14371430

@@ -1469,100 +1462,94 @@
14691462
*/
14701463
onDragMove: function(pointer, event) {
14711464
var newOffset = this.getEventPosition(event),
1472-
newMinOffset, newMaxOffset,
14731465
newMinValue, newMaxValue;
14741466

14751467
if (newOffset <= this.dragging.lowLimit) {
14761468
if (this.minH.rzsp === 0)
14771469
return;
14781470
newMinValue = this.minValue;
1479-
newMinOffset = 0;
14801471
newMaxValue = this.minValue + this.dragging.difference;
1481-
newMaxOffset = this.valueToOffset(newMaxValue);
14821472
} else if (newOffset >= this.maxPos - this.dragging.highLimit) {
14831473
if (this.maxH.rzsp === this.maxPos)
14841474
return;
14851475
newMaxValue = this.maxValue;
1486-
newMaxOffset = this.maxPos;
14871476
newMinValue = this.maxValue - this.dragging.difference;
1488-
newMinOffset = this.valueToOffset(newMinValue);
14891477
} else {
14901478
newMinValue = this.offsetToValue(newOffset - this.dragging.lowLimit);
14911479
newMinValue = this.roundStep(newMinValue);
1492-
newMinOffset = this.valueToOffset(newMinValue);
14931480
newMaxValue = newMinValue + this.dragging.difference;
1494-
newMaxOffset = this.valueToOffset(newMaxValue);
14951481
}
14961482

1497-
this.positionTrackingBar(newMinValue, newMaxValue, newMinOffset, newMaxOffset);
1483+
this.positionTrackingBar(newMinValue, newMaxValue);
14981484
},
14991485

15001486
/**
15011487
* Set the new value and offset for the entire bar
15021488
*
15031489
* @param {number} newMinValue the new minimum value
15041490
* @param {number} newMaxValue the new maximum value
1505-
* @param {number} newMinOffset the new minimum offset
1506-
* @param {number} newMaxOffset the new maximum offset
15071491
*/
1508-
positionTrackingBar: function(newMinValue, newMaxValue, newMinOffset, newMaxOffset) {
1492+
positionTrackingBar: function(newMinValue, newMaxValue) {
15091493
this.scope.rzSliderModel = newMinValue;
15101494
this.scope.rzSliderHigh = newMaxValue;
1511-
this.updateHandles('rzSliderModel', newMinOffset);
1512-
this.updateHandles('rzSliderHigh', newMaxOffset);
1495+
this.updateHandles('rzSliderModel', this.valueToOffset(newMinValue));
1496+
this.updateHandles('rzSliderHigh', this.valueToOffset(newMaxValue));
15131497
this.applyModel();
15141498
},
15151499

15161500
/**
15171501
* Set the new value and offset to the current tracking handle
15181502
*
15191503
* @param {number} newValue new model value
1520-
* @param {number} newOffset new offset value
15211504
*/
1522-
positionTrackingHandle: function(newValue, newOffset) {
1505+
positionTrackingHandle: function(newValue) {
15231506
var valueChanged = false;
1524-
var switched = false;
15251507

15261508
if (this.range) {
15271509
newValue = this.applyMinRange(newValue);
1528-
newOffset = this.valueToOffset(newValue);
15291510
/* This is to check if we need to switch the min and max handles */
1530-
if (this.tracking === 'rzSliderModel' && newValue >= this.scope.rzSliderHigh) {
1531-
switched = true;
1532-
this.scope[this.tracking] = this.scope.rzSliderHigh;
1533-
this.updateHandles(this.tracking, this.maxH.rzsp);
1534-
this.updateAriaAttributes();
1535-
this.tracking = 'rzSliderHigh';
1536-
this.minH.removeClass('rz-active');
1537-
this.maxH.addClass('rz-active');
1538-
if (this.options.keyboardSupport)
1539-
this.focusElement(this.maxH);
1511+
if (this.tracking === 'rzSliderModel' && newValue > this.scope.rzSliderHigh) {
1512+
if (this.options.noSwitching && this.scope.rzSliderHigh !== this.minValue) {
1513+
newValue = this.applyMinRange(this.scope.rzSliderHigh);
1514+
}
1515+
else {
1516+
this.scope[this.tracking] = this.scope.rzSliderHigh;
1517+
this.updateHandles(this.tracking, this.maxH.rzsp);
1518+
this.updateAriaAttributes();
1519+
this.tracking = 'rzSliderHigh';
1520+
this.minH.removeClass('rz-active');
1521+
this.maxH.addClass('rz-active');
1522+
if (this.options.keyboardSupport)
1523+
this.focusElement(this.maxH);
1524+
}
15401525
valueChanged = true;
1541-
} else if (this.tracking === 'rzSliderHigh' && newValue <= this.scope.rzSliderModel) {
1542-
switched = true;
1543-
this.scope[this.tracking] = this.scope.rzSliderModel;
1544-
this.updateHandles(this.tracking, this.minH.rzsp);
1545-
this.updateAriaAttributes();
1546-
this.tracking = 'rzSliderModel';
1547-
this.maxH.removeClass('rz-active');
1548-
this.minH.addClass('rz-active');
1549-
if (this.options.keyboardSupport)
1550-
this.focusElement(this.minH);
1526+
} else if (this.tracking === 'rzSliderHigh' && newValue < this.scope.rzSliderModel) {
1527+
if (this.options.noSwitching && this.scope.rzSliderModel !== this.maxValue) {
1528+
newValue = this.applyMinRange(this.scope.rzSliderModel);
1529+
}
1530+
else {
1531+
this.scope[this.tracking] = this.scope.rzSliderModel;
1532+
this.updateHandles(this.tracking, this.minH.rzsp);
1533+
this.updateAriaAttributes();
1534+
this.tracking = 'rzSliderModel';
1535+
this.maxH.removeClass('rz-active');
1536+
this.minH.addClass('rz-active');
1537+
if (this.options.keyboardSupport)
1538+
this.focusElement(this.minH);
1539+
}
15511540
valueChanged = true;
15521541
}
15531542
}
15541543

15551544
if (this.scope[this.tracking] !== newValue) {
15561545
this.scope[this.tracking] = newValue;
1557-
this.updateHandles(this.tracking, newOffset);
1546+
this.updateHandles(this.tracking, this.valueToOffset(newValue));
15581547
this.updateAriaAttributes();
15591548
valueChanged = true;
15601549
}
15611550

1562-
if (valueChanged) {
1551+
if (valueChanged)
15631552
this.applyModel();
1564-
}
1565-
return switched;
15661553
},
15671554

15681555
applyMinRange: function(newValue) {

0 commit comments

Comments
 (0)