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
  • I think what you have is better, check this answer as well stackoverflow.com/questions/15656617/… Commented Oct 19, 2014 at 18:09
  • There are some interesting discussions related to this here as well. github.com/angular/angular.js/issues/2404 Commented Oct 19, 2014 at 18:13
  • Thanks I read this both links several times, and some others, but I did not catch if this is an expected behaviour or a bug ? Commented Oct 19, 2014 at 20:03

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I've seen similar solutions, maybe the exact solution elsewhere. But, this one made the most sense to me.
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 Comments

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...
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
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)
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.

Comments

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.