Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

ng-model does not set initial value and position of input[type=range] #6726

Closed

Description

@fschwiet

Basically, a range input is set up with an initial value using ng-model. The actual value of the HTML element, and the position of the range slider, are incorrect. I would expect the slider position and html input value to be in sync with the model variable.

Here is a repro: http://jsfiddle.net/fschwiet/HVp2J/

Verified on chrome and firefox running on Windows 8.

I see there are other issues opened for input[type=range], its not clear they are related.

Activity

  1. self-assigned this
    on Mar 17, 2014
  2. added this to the milestone on Mar 17, 2014
  3. IgorMinar commented on Mar 17, 2014

    @IgorMinar
    Contributor

    This is still an issue with Angular 1.2.14: http://jsfiddle.net/HVp2J/7/

  4. removed their assignment
    on Mar 17, 2014
  5. fschwiet commented on Mar 17, 2014

    @fschwiet
    Author

    As a work-around, one can set the model value within a $timeout handler.

  6. Rajat-Chowdhary commented on Mar 18, 2014

    @Rajat-Chowdhary

    $timeout doesn' help, the issue remains.

    @fschwiet : http://jsfiddle.net/HVp2J/9/

  7. fschwiet commented on Mar 18, 2014

    @fschwiet
    Author

    @Rajat-Chowdhary Sorry, I should have included a code sample showing how $timeout can work as work-around: http://jsfiddle.net/fschwiet/YC4av/

    The workaround does feel dicey since the model value cannot be initialized until the $timeout callback for the workaround to work.

  8. ardf69 commented on Apr 24, 2014

    @ardf69

    It seems I found the problem.
    Angular sets value before setting min, max and step so it seems that the range is in the wrong position. To solve the problem I used this directive

    angular.module('angular-range', []).directive('range', function() {
        return {
            replace: true,
            restrict: 'E',
            scope: {
                value: '=ngModel',
                min: '=rangeMin',
                max: '=rangeMax',
                step: '=rangeStep',
            },
            template: '<input type="range"/>',
            link: function(scope, iElement, iAttrs) {
                scope.$watch('min', function() { setValue(); });
                scope.$watch('max', function() { setValue(); });
                scope.$watch('step', function() { setValue(); });
                scope.$watch('value', function() { setValue(); });
    
                function setValue() {
                    if (
                        angular.isDefined(scope.min) &&
                        angular.isDefined(scope.max) &&
                        angular.isDefined(scope.step) &&
                        angular.isDefined(scope.value)
                    ) {
                        iElement.attr("min", scope.min);
                        iElement.attr("max", scope.max);
                        iElement.attr("step", scope.step);
                        iElement.val(scope.value); 
                    }
                }
                function read() {
                    scope.value = iElement.val();
                }
    
                iElement.on('change', function() {
                    scope.$apply(read);
                });
            }
        };
    });
    
  9. ardf69 commented on Jun 23, 2014

    @ardf69

    Here there is the new version of ngRange without private scope:

    angular
    .module('ngRange', [])
    .directive('ngRange', function() {
        return {
            replace: true,
            restrict: 'E',
            require: 'ngModel',
            template: '<input type="range"></input>',
            link: function(scope, element, attrs, ngModel) {
                var ngRangeMin;
                var ngRangeMax;
                var ngRangeStep;
                var value;
    
                if (!angular.isDefined(attrs.ngRangeMin)) {
                    ngRangeMin = 0;
                } else {
                    scope.$watch(attrs.ngRangeMin, function(newValue, oldValue, scope) {
                        if (angular.isDefined(newValue)) {
                            ngRangeMin = newValue;
                            setValue();
                        }
                    });
                }
                if (!angular.isDefined(attrs.ngRangeMax)) {
                    ngRangeMax = 100;
                } else {
                    scope.$watch(attrs.ngRangeMax, function(newValue, oldValue, scope) {
                        if (angular.isDefined(newValue)) {
                            ngRangeMax = newValue;
                            setValue();
                        }
                    });
                }
                if (!angular.isDefined(attrs.ngRangeStep)) {
                    ngRangeStep = 1;
                } else {
                    scope.$watch(attrs.ngRangeStep, function(newValue, oldValue, scope) {
                        if (angular.isDefined(newValue)) {
                            ngRangeStep = newValue;
                            setValue();
                        }
                    });
                }
                if (!angular.isDefined(ngModel)) {
                    value = 50;
                } else {
                    scope.$watch(
                        function () {
                            return ngModel.$modelValue;
                        }, 
                        function(newValue, oldValue, scope) {
                            if (angular.isDefined(newValue)) {
                                value = newValue;
                                setValue();
                            }
                        }
                    );
                }
    
                function setValue() {
                    if (
                        angular.isDefined(ngRangeMin) &&
                        angular.isDefined(ngRangeMax) &&
                        angular.isDefined(ngRangeStep) &&
                        angular.isDefined(value)
                    ) {
                        element.attr("min", ngRangeMin);
                        element.attr("max", ngRangeMax);
                        element.attr("step", ngRangeStep);
                        element.val(value); 
                    }
                }
    
                function read() {
                    if (angular.isDefined(ngModel)) {
                        ngModel.$setViewValue(value);
                    }
                }
    
                element.on('change', function() {
                    if (angular.isDefined(value) && (value != element.val())) {
                        value = element.val();
                        scope.$apply(read);
                    }
                });
            }
        };
    });
    
  10. zavidovych commented on Dec 3, 2014

    @zavidovych
  11. 17 remaining items

  12. davedx commented on Mar 1, 2016

    @davedx
    Contributor

    Another lazy workaround hack:

          $timeout(function () {
            angular.element('.slider-input').val(amount);
          });
    
  13. cue232s commented on Mar 14, 2016

    @cue232s

    +1

  14. roryokane commented on Mar 14, 2016

    @roryokane

    With GitHub’s new Reactions feature, you no longer need to comment “+1”. Instead, you can mark your interest by clicking the “+:smile:” at the top-right of the first comment in this issue, then choosing :+1: (“+1”). This avoids sending a useless notification to everyone subscribed to this issue.

  15. nagarajumusini commented on Mar 18, 2016

    @nagarajumusini

    I have solved my problem using ondrag method by removing ng-model.
    check this http://codepen.io/nagarajumusini/pen/BKpGJz

  16. marianmazarovici commented on Apr 13, 2016

    @marianmazarovici

    +1

  17. felixschul commented on May 18, 2016

    @felixschul

    +1

  18. Jerome2606 commented on May 22, 2016

    @Jerome2606

    Adding ng-init to input works for me to set initial value

    <input type="range" class="slider-years" min="0" max="30" step="1" value="0" data-ng-model="metier.anneeExperience" data-ng-init="metier.anneeExperience ? metier.anneeExperience = metier.anneeExperience : metier.anneeExperience = 0" />

    Found solution in:

    http://jsfiddle.net/jestho/8dymV/7/

  19. modified the milestones: 1.5.x, on Jun 15, 2016
  20. Narretz commented on Jul 5, 2016

    @Narretz
    Contributor

    We are working on this (finally). Closing as a duplicate of #5892

  21. jacobbullock95 commented on Jul 6, 2016

    @jacobbullock95

    $(document).ready(function () {
    angular.element('.yourclasshere').val(valueoftheslideronload);
    });

    this jQuery workaround works so you can set a value when the page loads but whatever ithe value of the slider controls wont sync until it's touched.

  22. mrdulin commented on Aug 3, 2016

    @mrdulin

    @davedx Maybe this is the best way before the issue is solved.

  23. AhmadRedha commented on Oct 1, 2016

    @AhmadRedha

    <input type="range" min="15" data-ng-init="signup.age=30" value="30" max="85" step="1" name="ageInput" class="form-control input-lg" ng-model="signup.age" oninput="ageOutputId.value = ageInput.value" /> <output name="ageOutputName" id="ageOutputId">30</output>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions