0

I try to initialize a slider using AngularJS, but the cursor show 100 when the value is over 100.

Setting the value 150 in a range [50,150] fails with this code :

<html ng-app="App">
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
	<script>
		angular.module('App', ['App.controllers']);
		angular.module('App.controllers', []).controller('AppController', function($scope) {
			$scope.min = 50;
			$scope.max = 150;
			$scope.value = 150;
		});		
	</script>
</head>
<body ng-controller="AppController" >
	{{min}}<input ng-model="value" min="{{min}}" max="{{max}}" type="range" />{{max}}<br/>
	value:{{value}}
</body>
</html>

The cursor is badly placed (it show 100 instead of 150). How to display the cursor to its correct place ?

An explanation of what occurs could be on this forum

Update
This bug is reported as issue #6726

Update
The issue #14982 is closed by the Pull Request 14996 and solve the issue see answer.

3

4 Answers 4

5

After searches and tries , a possible way is to define a custom directive :

<html ng-app="App">
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
	<script>
		angular.module('App', ['App.controllers']);
		angular.module('App.controllers', []).controller('AppController', function($scope) {
			$scope.min = 50;
			$scope.max = 150;
			$scope.value = 150;
		}).directive('ngMin', function() {
			return {
				restrict: 'A',
				require: 'ngModel',
				link: function(scope, elem, attr) { elem.attr('min', attr.ngMin); }
			};
		}).directive('ngMax', function() {
			return {
				restrict: 'A',
				require: 'ngModel',
				link: function(scope, elem, attr) { elem.attr('max', attr.ngMax); }
			};
		});		
	</script>
</head>
<body ng-controller="AppController" >
	{{min}}<input ng-model="value" ng-min="{{min}}" ng-max="{{max}}" type="range" />{{max}}<br/>
	value:{{value}}
</body>
</html>

Even it is working this is a non standard extension in order to manage a very basic use case.

1
  • I've seen similar solutions, maybe the exact solution elsewhere. But, this one made the most sense to me.
    – E.E.33
    Commented Mar 14, 2016 at 6:17
2

Try this new one.

You can configure angular to make it interpolate these values. And you can use your initial code after that ...

Isn't it magic ?

Use this code only once in your app. Once angular is configured, it will be working for all the future ranges you will use.

<html ng-app="App">
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script>
        angular.module('App', ['App.controllers']);
        angular.module('App.controllers', [])
        /* Modify angular to make it interpolate min and max, for ngModel when type = range */
        .config(['$provide', function($provide) {
            $provide.decorator('ngModelDirective', ['$delegate', function($delegate) {
                var ngModel = $delegate[0], controller = ngModel.controller;
                ngModel.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
                    if ('range' === attrs.type) {
                        var $interpolate = $injector.get('$interpolate');
                        attrs.$set('min', $interpolate(attrs.min || '')(scope));
                        attrs.$set('max', $interpolate(attrs.max || '')(scope));
                        $injector.invoke(controller, this, {
                            '$scope': scope,
                            '$element': element,
                            '$attrs': attrs
                        });
                    }
                }];
                return $delegate;
             }]);
         }])
         .controller('AppController', function($scope) {
             $scope.min = 50;
             $scope.max = 150;
             $scope.value = 150;
         });			
</script>
</head>
<body ng-controller="AppController" >
	{{min}}<input ng-model="value" min="{{min}}" max="{{max}}" type="range"/>{{max}}<br/>
	value:{{value}}
</body>
</html>

3
  • OK, I see what you mean. The cleanest then, is to configure angular engine directly. I edited my answer, try this new snippet ... and tell me... Commented Oct 22, 2014 at 10:13
  • I unaccept your answer because it works by side effects. Replacing attrs.$set('max', $interpolate(attrs.max || '')(scope)); with attrs.$set('max', ''); sill trig the update. It doesnot works with 2 sliders and this bug is referenced in angularJs issues github.com/angular/angular.js/issues/6726
    – mpromonet
    Commented Jan 20, 2015 at 12:01
  • You are right, the pb was about the cursor value and not the range setup. Sorry about that, I did not get it by the time. But for a reason I don't really understand my workaround still does work : plnkr.co/edit/VuqxFv4Ni72TYbK00dqp?p=preview (even with two sliders) Commented Jan 20, 2015 at 15:06
2

My lazy way of addressing this bug was to divide the min/max and step values by 100. So 300 becomes 3.0, etc. and values fall below 100. Then I multiply things back as needed.

0

Since this commit, the initial code give the expected result.
Using release 1.6.0 allow to original code to show slider correctly :

<html ng-app="App">
<head>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js"></script>
	<script>
		angular.module('App', ['App.controllers']);
		angular.module('App.controllers', []).controller('AppController', function($scope) {
			$scope.min = 50;
			$scope.max = 150;
			$scope.value = 150;
		});		
	</script>
</head>
<body ng-controller="AppController" >
	{{min}}<input ng-model="value" min="{{min}}" max="{{max}}" type="range" />{{max}}<br/>
	value:{{value}}
</body>
</html>

Not the answer you're looking for? Browse other questions tagged or ask your own question.