@@ -12,158 +12,183 @@ angular.module('ui.bootstrap-slider', [])
12
12
value : "=" ,
13
13
ngModel : '=' ,
14
14
range :'=' ,
15
- sliderid :'=' ,
16
- formater :'&' ,
15
+ sliderid : '=' ,
16
+ formater : '&' ,
17
17
onStartSlide : '&' ,
18
18
onStopSlide : '&' ,
19
19
onSlide : '&'
20
20
} ,
21
21
link : function ( $scope , element , attrs , ngModelCtrl , $compile ) {
22
+ var ngModelDeregisterFn , ngDisabledDeregisterFn ;
23
+
22
24
initSlider ( ) ;
23
25
24
26
function initSlider ( ) {
27
+ var options = { } ;
25
28
26
- if ( attrs . ngChange ) {
27
- ngModelCtrl . $viewChangeListeners . push ( function ( ) {
28
- $scope . $apply ( attrs . ngChange ) ;
29
- } ) ;
29
+ function setOption ( key , value , defaultValue ) {
30
+ options [ key ] = value || defaultValue ;
30
31
}
31
-
32
- $ . fn . slider . Constructor . prototype . disable = function ( ) {
33
- this . picker . off ( ) ;
34
- } ;
35
-
36
- $ . fn . slider . Constructor . prototype . enable = function ( ) {
37
- this . picker . on ( ) ;
38
- } ;
39
-
40
- if ( attrs . ngChange ) {
41
- ngModelCtrl . $viewChangeListeners . push ( function ( ) {
42
- $scope . $apply ( attrs . ngChange ) ;
43
- } ) ;
32
+ function setFloatOption ( key , value , defaultValue ) {
33
+ options [ key ] = value ? parseFloat ( value ) : defaultValue ;
44
34
}
45
-
46
- var options = { } ;
47
- if ( $scope . sliderid ) options . id = $scope . sliderid ;
48
- if ( $scope . min ) options . min = parseFloat ( $scope . min ) ;
49
- if ( $scope . max ) {
50
- options . max = parseFloat ( $scope . max ) ;
35
+ function setBooleanOption ( key , value , defaultValue ) {
36
+ options [ key ] = value ? value + '' === 'true' : defaultValue ;
37
+ }
38
+ function getArrayOrValue ( value ) {
39
+ return ( angular . isString ( value ) && value . indexOf ( "[" ) === 0 ) ? angular . fromJson ( value ) : value ;
51
40
}
52
41
42
+ setOption ( 'id' , $scope . sliderid ) ;
43
+ setOption ( 'orientation' , attrs . orientation , 'horizontal' ) ;
44
+ setOption ( 'selection' , attrs . selection , 'before' ) ;
45
+ setOption ( 'handle' , attrs . handle , 'round' ) ;
46
+ setOption ( 'tooltip' , attrs . tooltip , 'show' ) ;
47
+ setOption ( 'tooltipseparator' , attrs . tooltipseparator , ':' ) ;
48
+
49
+ setFloatOption ( 'min' , $scope . min , 0 ) ;
50
+ setFloatOption ( 'max' , $scope . max , 10 ) ;
51
+ setFloatOption ( 'step' , $scope . step , 1 ) ;
52
+ var strNbr = options . step + '' ;
53
+ var decimals = strNbr . substring ( strNbr . lastIndexOf ( '.' ) + 1 ) ;
54
+ setFloatOption ( 'precision' , attrs . precision , decimals ) ;
55
+
56
+ setBooleanOption ( 'tooltip_split' , attrs . tooltipsplit , false ) ;
57
+ setBooleanOption ( 'enabled' , attrs . enabled , true ) ;
58
+ setBooleanOption ( 'naturalarrowkeys' , attrs . naturalarrowkeys , false ) ;
59
+ setBooleanOption ( 'reversed' , attrs . reversed , false ) ;
53
60
54
- if ( attrs . step ) options . step = parseFloat ( $scope . step ) ;
55
- if ( attrs . precision ) options . precision = parseFloat ( attrs . precision ) ;
56
- if ( attrs . orientation ) options . orientation = attrs . orientation ;
57
61
if ( $scope . value ) {
58
62
if ( angular . isNumber ( $scope . value ) || angular . isArray ( $scope . value ) ) {
59
63
options . value = $scope . value ;
60
- } else if ( angular . isString ( $scope . value ) ) {
61
- if ( attrs . value . indexOf ( "[" ) === 0 ) {
62
- options . value = angular . fromJson ( $scope . value ) ;
63
- } else {
64
+ }
65
+ else if ( angular . isString ( $scope . value ) ) {
66
+ options . value = getArrayOrValue ( $scope . value ) ;
67
+ if ( ! angular . isArray ( options . value ) ) {
64
68
options . value = parseFloat ( $scope . value ) ;
65
69
}
66
70
}
67
71
}
68
- if ( $scope . range ) {
69
- options . range = $scope . range === true ;
70
- }
71
72
72
- if ( attrs . selection ) options . selection = attrs . selection ;
73
- if ( attrs . tooltip ) options . tooltip = attrs . tooltip ;
74
- if ( attrs . tooltipseparator ) options . tooltip_separator = attrs . tooltipseparator ;
75
- if ( attrs . tooltipsplit ) options . tooltip_split = attrs . tooltipsplit === 'true' ;
76
- if ( attrs . handle ) options . handle = attrs . handle ;
77
- if ( attrs . reversed ) options . reversed = attrs . reversed === 'true' ;
78
- if ( attrs . enabled ) options . enabled = attrs . enabled === 'true' ;
79
- if ( attrs . naturalarrowkeys ) options . natural_arrow_keys = attrs . naturalarrowkeys === 'true' ;
80
- if ( attrs . formater ) options . formater = $scope . $eval ( $scope . formater ) ;
81
-
82
- if ( options . range && ! options . value ) {
83
- options . value = [ 0 , 0 ] ; // This is needed, because of value defined at $.fn.slider.defaults - default value 5 prevents creating range slider
84
- }
85
-
86
- var slider = $ ( element . find ( ".slider-input" ) [ 0 ] ) . slider ( options ) ;
87
- slider . slider ( 'destroy' ) ;
88
- slider = $ ( element . find ( ".slider-input" ) [ 0 ] ) . slider ( options ) ;
89
-
90
- var updateEvent ;
91
- if ( angular . isString ( attrs . updateevent ) ) {
92
- // check if array of event names
93
- if ( attrs . updateevent . indexOf ( "[" ) === 0 ) {
94
- updateEvent = angular . fromJson ( attrs . updateevent ) ;
73
+ setBooleanOption ( 'range' , $scope . range , false ) ;
74
+ if ( options . range ) {
75
+ if ( angular . isArray ( $scope . value ) ) {
76
+ options . value = $scope . value ;
77
+ }
78
+ else if ( angular . isString ( $scope . value ) ) {
79
+ options . value = getArrayOrValue ( $scope . value ) ;
80
+ if ( ! angular . isArray ( options . value ) ) {
81
+ var value = parseFloat ( $scope . value ) ;
82
+ if ( value < $scope . min ) {
83
+ value = $scope . min ;
84
+ options . value = [ value , options . max ] ;
85
+ }
86
+ else if ( value > $scope . max ) {
87
+ value = $scope . max ;
88
+ options . value = [ options . min , value ] ;
89
+ }
90
+ }
95
91
}
96
92
else {
97
- // if only single event name in string
98
- updateEvent = [ attrs . updateevent ] ;
93
+ options . value = [ options . min , options . max ] ; // This is needed, because of value defined at $.fn.slider.defaults - default value 5 prevents creating range slider
99
94
}
95
+ $scope . ngModel = options . value ; // needed, otherwise turns value into [null, ##]
100
96
}
101
97
else {
102
- // default to slide event
103
- updateEvent = [ 'slide' ] ;
98
+ setFloatOption ( 'value' , $scope . value , 5 ) ;
104
99
}
105
100
106
- angular . forEach ( updateEvent , function ( sliderEvent ) {
107
- slider . on ( sliderEvent , function ( ev ) {
108
- ngModelCtrl . $setViewValue ( ev . value ) ;
109
- $timeout ( function ( ) {
110
- $scope . $apply ( ) ;
111
- } ) ;
112
- } ) ;
113
- } ) ;
114
-
115
- // Event listeners
116
- var sliderEvents = {
117
- slideStart : 'onStartSlide' ,
118
- slide : 'onSlide' ,
119
- slideStop : 'onStopSlide'
120
- } ;
121
-
122
- angular . forEach ( sliderEvents , function ( sliderEventAttr , sliderEvent ) {
123
- slider . on ( sliderEvent , function ( ev ) {
124
-
125
- if ( $scope [ sliderEventAttr ] ) {
126
- var invoker = $parse ( attrs [ sliderEventAttr ] ) ;
127
- invoker ( $scope . $parent , { $event : ev , value : ev . value } ) ;
128
-
129
- $timeout ( function ( ) {
101
+ if ( $scope . formater ) options . formater = $scope . $eval ( $scope . formater ) ;
102
+
103
+ var slider = element . find ( ".slider-input" ) . eq ( 0 ) ;
104
+ // check if slider jQuery plugin exists
105
+ if ( $ . fn . slider ) {
106
+ // adding methods to jQuery slider plugin prototype
107
+ $ . fn . slider . Constructor . prototype . disable = function ( ) {
108
+ this . picker . off ( ) ;
109
+ } ;
110
+ $ . fn . slider . Constructor . prototype . enable = function ( ) {
111
+ this . picker . on ( ) ;
112
+ } ;
113
+
114
+ // destroy previous slider to reset all options
115
+ slider . slider ( options ) ;
116
+ slider . slider ( 'destroy' ) ;
117
+ slider . slider ( options ) ;
118
+
119
+ // everything that needs slider element
120
+ var updateEvent = getArrayOrValue ( attrs . updateevent ) ;
121
+ if ( angular . isString ( updateEvent ) ) {
122
+ // if only single event name in string
123
+ updateEvent = [ updateEvent ] ;
124
+ }
125
+ else {
126
+ // default to slide event
127
+ updateEvent = [ 'slide' ] ;
128
+ }
129
+ angular . forEach ( updateEvent , function ( sliderEvent ) {
130
+ slider . on ( sliderEvent , function ( ev ) {
131
+ ngModelCtrl . $setViewValue ( ev . value ) ;
132
+ $timeout ( function ( ) {
130
133
$scope . $apply ( ) ;
131
- } ) ;
132
- }
133
- } ) ;
134
- } ) ;
135
-
134
+ } ) ;
135
+ } ) ;
136
+ } ) ;
137
+
138
+ // Event listeners
139
+ var sliderEvents = {
140
+ slideStart : 'onStartSlide' ,
141
+ slide : 'onSlide' ,
142
+ slideStop : 'onStopSlide'
143
+ } ;
144
+ angular . forEach ( sliderEvents , function ( sliderEventAttr , sliderEvent ) {
145
+ slider . on ( sliderEvent , function ( ev ) {
146
+
147
+ if ( $scope [ sliderEventAttr ] ) {
148
+ var invoker = $parse ( attrs [ sliderEventAttr ] ) ;
149
+ invoker ( $scope . $parent , { $event : ev , value : ev . value } ) ;
150
+
151
+ $timeout ( function ( ) {
152
+ $scope . $apply ( ) ;
153
+ } ) ;
154
+ }
155
+ } ) ;
156
+ } ) ;
157
+
158
+ if ( attrs . ngChange ) {
159
+ ngModelCtrl . $viewChangeListeners . push ( function ( ) {
160
+ $scope . $apply ( attrs . ngChange ) ;
161
+ } ) ;
162
+ }
136
163
137
- if ( angular . isDefined ( attrs . ngDisabled ) ) {
138
- $scope . $watch ( attrs . ngDisabled , function ( value ) {
139
- if ( value ) {
140
- slider . slider ( 'disable' ) ;
141
- } else {
142
- slider . slider ( 'enable' ) ;
143
- }
144
- } ) ;
164
+ // deregister ngDisabled watcher to prevent memory leaks
165
+ if ( angular . isFunction ( ngDisabledDeregisterFn ) ) {
166
+ ngDisabledDeregisterFn ( ) ;
167
+ ngDisabledDeregisterFn = null ;
168
+ }
169
+ if ( angular . isDefined ( attrs . ngDisabled ) ) {
170
+ ngDisabledDeregisterFn = $scope . $watch ( attrs . ngDisabled , function ( value ) {
171
+ if ( value ) {
172
+ slider . slider ( 'disable' ) ;
173
+ }
174
+ else {
175
+ slider . slider ( 'enable' ) ;
176
+ }
177
+ } ) ;
178
+ }
179
+ // deregister ngModel watcher to prevent memory leaks
180
+ if ( angular . isFunction ( ngModelDeregisterFn ) ) ngModelDeregisterFn ( ) ;
181
+ ngModelDeregisterFn = $scope . $watch ( 'ngModel' , function ( value ) {
182
+ slider . slider ( 'setValue' , value ) ;
183
+ } ) ;
145
184
}
185
+ }
146
186
147
-
148
- $scope . $watch ( 'ngModel' , function ( value ) {
149
- slider . slider ( 'setValue' , value ) ;
187
+ var watchers = [ 'min' , 'max' , 'step' , 'range' ] ;
188
+ angular . forEach ( watchers , function ( prop ) {
189
+ $scope . $watch ( prop , function ( ) {
190
+ initSlider ( ) ;
150
191
} ) ;
151
- } ;
152
-
153
- $scope . $watch ( 'max' , function ( value ) {
154
- initSlider ( ) ;
155
- } ) ;
156
-
157
- $scope . $watch ( 'min' , function ( value ) {
158
- initSlider ( ) ;
159
- } ) ;
160
-
161
- $scope . $watch ( 'step' , function ( value ) {
162
- initSlider ( ) ;
163
- } ) ;
164
-
165
- $scope . $watch ( 'range' , function ( value ) {
166
- initSlider ( ) ;
167
192
} ) ;
168
193
}
169
194
} ;
0 commit comments