Angular.js: ng-modelはinput [type = range]の初期値と位置を設定しません

作成日 2014年03月18日  ·  35コメント  ·  ソース: angular/angular.js

基本的に、範囲入力はng-modelを使用して初期値で設定されます。 HTML要素の実際の値、および範囲スライダーの位置が正しくありません。 スライダーの位置とhtml入力値がモデル変数と同期していると思います。

ここに再現があります: http

Windows8で実行されているchromeとfirefoxで検証済み。

input [type = range]に対して開かれている他の問題があるようですが、それらが関連していることは明らかではありません。

forms moderate duplicate broken expected use bug

最も参考になるコメント

GitHubの新しいリアクション機能により、「+ 1」にコメントする必要がなくなりました。 代わりに、この号の最初のコメントの右上にある「+:smile:」をクリックしてから、:+ 1 :(「+ 1」)を選択することで、関心を示すことができます。 これにより、この問題を購読しているすべての人に無駄な通知を送信することを回避できます。

全てのコメント35件

これはAngular1.2.14の問題です: http ://jsfiddle.net/HVp2J/7/

回避策として、$ timeoutハンドラー内でモデル値を設定できます。

$ timeoutは役に立ちませんが、問題は残ります。

@fschwiethttp//jsfiddle.net/HVp2J/9/

@ Rajat-Chowdhary申し訳ありませんが、$ timeoutが回避としてどのように機能するかを示すコードサンプルを含める必要がありました: //jsfiddle.net/fschwiet/YC4av/

回避策が機能するための$ timeoutコールバックまでモデル値を初期化できないため、回避策は危険を感じます。

問題を見つけたようです。
Angularは、最小、最大、ステップを設定する前に値を設定するため、範囲が間違った位置にあるように見えます。 問題を解決するために、私はこのディレクティブを使用しました

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);
            });
        }
    };
});

プライベートスコープのない新しいバージョンのngRangeがあります。

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

これはまだ問題ですよね?

http://plnkr.co/edit/MAT5KPkXyWblAJ71L8nK?p=preview

うん+1

はい、まだ問題です。

値が100を超えているときにAngularJSを使用してinput [range]の値を初期化する方法をstackoverflowで同様のことを尋ねました。 1.4.0-beta.build.3791を使用すると、このバグはまだ存在します。

+1

+1であり、入力範囲が入力番号と結合されたときに最悪になりました。

この問題の+1

同じ問題に直面している:+1

うん-同じ問題+1

これは基本的なhtml5です-これのステータスは何ですか、誰かがこれに取り組んでいますか?

これを考慮に入れて: https
ここで、エラー: ngModel:numfmt範囲スライダーがスローされます
私はこれに@ ardf69ソリューションを調整しました:

angular.module('common').directive('rangeSlider', [function () {
    return {
        replace: true,
        restrict: 'E',
        require: 'ngModel',
        template: '<input type="range"/>',
        link: function (scope, element, attrs, ngModel) {
            var ngRangeMin;
            var ngRangeMax;
            var ngRangeStep;
            var value;

            function init() {
                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();
                            }
                        }
                    );
                }

                if (!ngModel) {
                    return;
                }
                ngModel.$parsers.push(function (value) {
                    var val = Number(value);
                    if (val !== val) {
                        val = undefined;
                    }
                    return val;
                });
            }

            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);
                }
            });

            init();
        }
    };
}
]);

+ 1、ng-ifで[input type = range]を切り替えるときに同じ問題が発生します

私もこの問題に遭遇し、それについてStack Overflowの質問を書きました。 「Angularでは、スコープ変数_before_ ngModelのbind属性が入力のvalueバインドします」 。 質問には、この問題を再現する実行可能なコードスニペットが含まれています。

いくつかの回避策は、StackOverflowに回答として投稿されています。 私の場合に当てはまるのは、 $inputElement.prop() DOM操作を使用して、 minmax 、およびstep (必要な属性)の値を設定することです。 カスタムディレクティブの基になる<input>valueが最初に設定される前に、このDOM操作を実行することで、問題を回避できます。

このバグに対処する私の怠惰な方法は、最小/最大値とステップ値を100で割ることでした。したがって、300は3.0などになり、値は100を下回ります。次に、必要に応じて乗算します。 おそらくそれは誰かに役立つでしょう。

+1これは非常に迷惑です。

+1

+1

+1

別の怠惰な回避策のハック:

      $timeout(function () {
        angular.element('.slider-input').val(amount);
      });

+1

GitHubの新しいリアクション機能により、「+ 1」にコメントする必要がなくなりました。 代わりに、この号の最初のコメントの右上にある「+:smile:」をクリックしてから、:+ 1 :(「+ 1」)を選択することで、関心を示すことができます。 これにより、この問題を購読しているすべての人に無駄な通知を送信することを回避できます。

ng-modelを削除して、ondragメソッドを使用して問題を解決しました。
これをチェックしてくださいhttp://codepen.io/nagarajumusini/pen/BKpGJz

+1

+1

入力にng-initを追加すると、初期値を設定できます

<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" />

解決策が見つかりました:

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

私たちはこれに(ついに)取り組んでいます。 https://github.com/angular/angular.js/issues/5892の複製として閉じる

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

このjQueryの回避策は機能するため、ページの読み込み時に値を設定できますが、スライダーコントロールの値は、タッチされるまで同期されません。

@davedx問題が解決する前に、これが最善の方法かもしれません。

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

このページは役に立ちましたか?
0 / 5 - 0 評価