Angular.js: O modelo ng não define o valor inicial e a posição de entrada [tipo = intervalo]

Criado em 18 mar. 2014  ·  35Comentários  ·  Fonte: angular/angular.js

Basicamente, uma entrada de intervalo é configurada com um valor inicial usando o modelo ng. O valor real do elemento HTML e a posição do controle deslizante de intervalo estão incorretos. Eu esperaria que a posição do controle deslizante e o valor de entrada html estivessem em sincronia com a variável do modelo.

Aqui está uma reprodução: http://jsfiddle.net/fschwiet/HVp2J/

Verificado no Chrome e Firefox em execução no Windows 8.

Vejo que há outros problemas abertos para entrada [type = range], não está claro se eles estão relacionados.

forms moderate duplicate broken expected use bug

Comentários muito úteis

Com o novo recurso Reactions do GitHub, você não precisa mais comentar “+1”. Em vez disso, você pode marcar seu interesse clicando em “+: sorrir:” no canto superior direito do primeiro comentário neste problema e, em seguida, escolher: +1: (“+1”). Isso evita o envio de uma notificação inútil para todos os inscritos neste problema.

Todos 35 comentários

Isso ainda é um problema com o Angular 1.2.14: http://jsfiddle.net/HVp2J/7/

Como solução alternativa, pode-se definir o valor do modelo em um manipulador $ timeout.

$ timeout não ajuda, o problema permanece.

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

@ Rajat-Chowdhary Desculpe, eu deveria ter incluído um exemplo de código mostrando como $ timeout pode funcionar como solução alternativa :

A solução alternativa parece arriscada, pois o valor do modelo não pode ser inicializado até o retorno de chamada $ timeout para que a solução alternativa funcione.

Parece que encontrei o problema.
Angular define o valor antes de definir min, max e step, de forma que parece que o intervalo está na posição errada. Para resolver o problema, usei esta diretiva

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

Aqui está a nova versão do ngRange sem escopo privado:

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

isso ainda é um problema, certo?

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

Sim +1

Sim, ainda é um problema.

Eu perguntei algo semelhante em stackoverflow como inicializar o valor de uma entrada [range] usando AngularJS quando o valor está acima de 100 . Usando 1.4.0-beta.build.3791, esse bug ainda está presente.

+1

+1, e ficou pior quando a faixa de entrada é acoplada a um número de entrada.

1 para este problema

Enfrentando o mesmo problema: +1

sim - mesmo problema +1

este é o HTML5 básico - qual é o status disso, alguém está trabalhando nisso?

levando isso em consideração: https://github.com/danielcrisp/angular-rangeslider/issues/51
onde Error: ngModel: numfmt controle deslizante de intervalo é lançado
Eu ajustei a solução @ ardf69 para isso:

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, tenho o mesmo problema ao alternar [tipo de entrada = intervalo] com ng-if

Também me deparei com esse problema e escrevi uma pergunta sobre Stack Overflow sobre isso, “Em Angular, vincular o atributo da variável de escopo _before_ ngModel vincula a entrada value . A questão inclui um trecho de código executável que reproduz esse problema.

Algumas soluções alternativas foram publicadas como respostas no Stack Overflow. O aplicável ao meu caso envolve o uso de manipulação DOM com $inputElement.prop() para definir os valores de min , max e step (quaisquer atributos necessários). Ao fazer essa manipulação DOM antes do meu directiva costume está subjacente <input> 's value é primeiro set, I evitar o problema.

Minha maneira preguiçosa de resolver esse bug era dividir os valores mín. / Máx. E os valores da etapa por 100. Assim, 300 se torna 3,0, etc. e os valores ficam abaixo de 100. Então, multiplico as coisas de volta conforme necessário. Talvez seja útil para alguém.

+1 Isso é muito chato.

+1

+1

+1

Outra solução alternativa preguiçosa:

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

+1

Com o novo recurso Reactions do GitHub, você não precisa mais comentar “+1”. Em vez disso, você pode marcar seu interesse clicando em “+: sorrir:” no canto superior direito do primeiro comentário neste problema e, em seguida, escolher: +1: (“+1”). Isso evita o envio de uma notificação inútil para todos os inscritos neste problema.

Resolvi meu problema usando o método ondrag removendo o modelo ng.
verifique este http://codepen.io/nagarajumusini/pen/BKpGJz

+1

+1

Adicionar ng-init à entrada funciona para mim para definir o valor inicial

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

Solução encontrada em:

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

Estamos trabalhando nisso (finalmente). Fechando como uma duplicata de https://github.com/angular/angular.js/issues/5892

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

esta solução alternativa do jQuery funciona para que você possa definir um valor quando a página for carregada, mas seja qual for o valor dos controles deslizantes, não sincronizará até que seja tocado.

@davedx Talvez esta seja a melhor maneira antes que o problema seja resolvido.

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

Esta página foi útil?
0 / 5 - 0 avaliações