输入字段插入符位置未正确设置

时间:2018-04-11 16:26:20

标签: javascript angularjs input caret

我在下面有一个<input type="text>字段

的指令
myApp.directive('onlyDecimal', function () 
{
    return {
      require: '?ngModel',
      link: function(scope, element, attrs, ngModelCtrl) 
      {
            if(!ngModelCtrl) 
            {
                return; 
            }

            ngModelCtrl.$parsers.push(function(val) 
            {
                if (angular.isUndefined(val)) 
                {
                    var val = "";
                }

                var clean = "";

                if(val !== null)
                {
                    clean = val.replace(/[^0-9\.]/g, "");
                }

                var start   = element[0].selectionStart;
                var end     = element[0].selectionEnd + clean.length - val.length;

                var negativeCheck   = clean.split("-");
                var decimalCheck    = clean.split(".");

                if(!angular.isUndefined(negativeCheck[1])) 
                {
                    negativeCheck[1] = negativeCheck[1].slice(0, negativeCheck[1].length);
                    clean = negativeCheck[0] + '-' + negativeCheck[1];

                    if(negativeCheck[0].length > 0) 
                    {
                        clean = negativeCheck[0];
                    }
                }

                if(!angular.isUndefined(decimalCheck[1])) 
                {
                    decimalCheck[1] = decimalCheck[1].slice(0,2);
                    clean           = decimalCheck[0] + "." + decimalCheck[1];
                }

                if (val !== clean) 
                {
                    ngModelCtrl.$setViewValue(clean);
                    ngModelCtrl.$render();
                }

                element[0].setSelectionRange(start, end);

                return clean;
            });

            element.bind("keypress", function(event) 
            {
                if(event.keyCode === 32) 
                {
                    event.preventDefault();
                }
            });

            var decimalCount = 2;
            var decimalPoint = ".";

            ngModelCtrl.$render = function() 
            {
                if (ngModelCtrl.$modelValue != null && ngModelCtrl.$modelValue >= 0) 
                {
                    if (typeof decimalCount === "number") 
                    {
                        element.val(ngModelCtrl.$modelValue.toFixed(decimalCount).toString().replace(".", ","));
                    } 
                    else 
                    {
                        element.val(ngModelCtrl.$modelValue.toString().replace(".", ","));
                    }
                }
            }

            element.on("change", function(e) 
            {
                var floatValue = parseFloat(element.val().replace(",", "."));

                if (!isNaN(floatValue) && typeof decimalCount === "number") 
                {
                    if (decimalCount === 0) 
                    {
                        element.val(parseInt(floatValue));
                    } 
                    else 
                    {
                        var strValue = floatValue.toFixed(decimalCount);
                        element.val(strValue.replace(".", decimalPoint));
                    }
                }
            });
        }
    };
});

该指令的目的是仅允许字段中的数字和1位小数。

假设我的值为50.00然后我将插入符号设置为位置0之前的值,并输入键b的无效值。在设置选择范围之前设置了console.log,我得到了这些值:

START: 0 END: 1
START: 0 END: 0

它运行两次,似乎仍然将插入符号移动到下一个位置。

1 个答案:

答案 0 :(得分:0)

您的代码中至少存在两个导致问题行为的问题:

  1. ngModelCtrl.$render中,您正在检查decimalCount的类型,以确定$modelValue是数字还是字符串。一旦开始输入,ngModelCtrl.$modelValue就会变成一个字符串,但是你的逻辑仍会尝试在其上调用.toFixed(),导致渲染异常,并阻止setSelectionRange被调用解析器。

  2. 您的格式化程序中未使用正在交换小数点逗号的逻辑。带有逗号的值将进入,创建clean的正则表达式将删除它,因为它期望小数。解决此问题后,您还必须修复最后valclean之间的比较,以便将小数点交换回clean中的逗号。

  3. 总的来说,我建议如下:

    1. if (typeof decimalCount === "number")交换为if (typeof ngModelCtrl.$modelValue === "number")
    2. 在生成clean
    3. 之前,将所有逗号替换为小数
    4. 将所有小数替换为clean中的逗号,然后再将其与原始val进行比较。