Angular.js: ng-model ne définit pas la valeur initiale et la position de l'entrée [type = plage]

Créé le 18 mars 2014  ·  35Commentaires  ·  Source: angular/angular.js

Fondamentalement, une entrée de plage est configurée avec une valeur initiale à l'aide de ng-model. La valeur réelle de l'élément HTML et la position du curseur de plage sont incorrectes. Je m'attendrais à ce que la position du curseur et la valeur d'entrée HTML soient synchronisées avec la variable de modèle.

Voici une repro: http://jsfiddle.net/fschwiet/HVp2J/

Vérifié sur Chrome et Firefox sous Windows 8.

Je vois qu'il y a d'autres problèmes ouverts à l'entrée [type = range], ce n'est pas clair qu'ils sont liés.

forms moderate duplicate broken expected use bug

Commentaire le plus utile

Avec la nouvelle fonctionnalité de réaction de GitHub, vous n'avez plus besoin de commenter «+1». À la place, vous pouvez marquer votre intérêt en cliquant sur le "+: sourire:" en haut à droite du premier commentaire de ce numéro, puis en choisissant: +1: ("+1"). Cela évite d'envoyer une notification inutile à tous les abonnés à ce problème.

Tous les 35 commentaires

C'est toujours un problème avec Angular 1.2.14: http://jsfiddle.net/HVp2J/7/

Pour contourner le problème, on peut définir la valeur du modèle dans un gestionnaire $ timeout.

$ timeout n'aide pas, le problème demeure.

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

@ Rajat-Chowdhary Désolé, j'aurais dû inclure un exemple de code montrant comment $ timeout peut fonctionner comme solution de rechange :

La solution de contournement semble risquée car la valeur du modèle ne peut pas être initialisée avant le rappel $ timeout pour que la solution de contournement fonctionne.

Il semble que j'ai trouvé le problème.
Angular définit la valeur avant de régler min, max et step, de sorte qu'il semble que la plage soit dans la mauvaise position. Pour résoudre le problème, j'ai utilisé cette 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);
            });
        }
    };
});

Voici la nouvelle version de ngRange sans portée privée:

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

c'est toujours un problème, non?

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

Oui +1

Oui, toujours un problème.

J'ai demandé quelque chose de similaire dans stackoverflow Comment initialiser la valeur d'une entrée [plage] en utilisant AngularJS lorsque la valeur est supérieure à 100 . En utilisant la version 1.4.0-beta.build.3791, ce bogue est toujours présent.

+1

+1, et il est devenu pire lorsque la plage d'entrée est couplée à un numéro d'entrée.

+1 pour ce numéro

Face au même problème: +1

oui - même problème +1

c'est du HTML5 de base - quel est le statut à ce sujet, est-ce que quelqu'un travaille là-dessus?

en tenant compte de ceci: https://github.com/danielcrisp/angular-rangeslider/issues/51
où Erreur: ngModel: le curseur de plage
J'ai ajusté la solution @ ardf69 à ceci:

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, j'ai le même problème lors de la commutation [type d'entrée = plage] avec ng-if

J'ai également rencontré ce problème et j'ai écrit une question à ce sujet: «Dans Angular, l'attribut de liaison de la variable de portée _before_ ngModel lie l'entrée value » . La question comprend un extrait de code exécutable qui reproduit ce problème.

Certaines solutions de contournement ont été publiées en tant que réponses sur Stack Overflow. Celui qui s'applique à mon cas implique l'utilisation de la manipulation DOM avec $inputElement.prop() pour définir les valeurs de min , max et step (selon les attributs nécessaires). En faisant cette manipulation DOM avant que ma directive personnalisée sous-jacente <input> value soit définie pour la première fois, j'évite le problème.

Ma façon paresseuse de résoudre ce bogue était de diviser les valeurs min / max et step par 100. Donc 300 devient 3.0, etc. et les valeurs tombent en dessous de 100. Ensuite, je multiplie les choses selon les besoins. C'est peut-être utile à quelqu'un.

+1 C'est très ennuyeux.

+1

+1

+1

Un autre hack de contournement paresseux:

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

+1

Avec la nouvelle fonctionnalité de réaction de GitHub, vous n'avez plus besoin de commenter «+1». À la place, vous pouvez marquer votre intérêt en cliquant sur le "+: sourire:" en haut à droite du premier commentaire de ce numéro, puis en choisissant: +1: ("+1"). Cela évite d'envoyer une notification inutile à tous les abonnés à ce problème.

J'ai résolu mon problème en utilisant la méthode ondrag en supprimant ng-model.
vérifiez ceci http://codepen.io/nagarajumusini/pen/BKpGJz

+1

+1

L'ajout de ng-init à l'entrée fonctionne pour moi pour définir la valeur initiale

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

Solution trouvée dans:

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

Nous y travaillons (enfin). Fermeture en double de https://github.com/angular/angular.js/issues/5892

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

cette solution de contournement jQuery fonctionne afin que vous puissiez définir une valeur lorsque la page se charge, mais quelle que soit la valeur des contrôles de curseur ne se synchronise pas tant qu'elle n'est pas touchée.

@davedx C'est peut-être le meilleur moyen avant de résoudre le problème.

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

Cette page vous a été utile?
0 / 5 - 0 notes