简体   繁体   English

输入栏插入符号的位置设置不正确

[英]Input field caret position not getting set correctly

I have this directive down below for a <input type="text> field 我在下面将这个指令用于<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));
                    }
                }
            });
        }
    };
});

The purpose of this directive is to only allow numbers and 1 decimal in the field. 该指令的目的是在字段中仅允许数字和1个小数。

Let's say I have a value of 50.00 I then set the caret before the value which would be position 0 and I enter an invalid value of the key b . 假设我有一个50.00的值,然后将插入号设置在位置0之前,然后输入密钥b的无效值。 I set a console.log before I set the selection range and I get these values: 在设置选择范围之前,我先设置了console.log,然后得到了这些值:

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

It runs twice and it seems to still move the caret to the next position. 它运行两次,似乎仍将插入号移动到下一个位置。

There are at least two issues in your code that are causing problematic behavior: 您的代码中至少有两个问题会导致出现问题的行为:

  1. In ngModelCtrl.$render , you are checking the type of decimalCount to determine if the $modelValue is a number or a string. ngModelCtrl.$render ,您正在检查decimalCount的类型,以确定$modelValue是数字还是字符串。 As soon as you start typing, ngModelCtrl.$modelValue becomes a string, but your logic still attempts to call .toFixed() on it, causing render to throw an exception, and preventing setSelectionRange from being called by the parser. 一旦开始键入, ngModelCtrl.$modelValue就会变成一个字符串,但是您的逻辑仍然尝试在其上调用.toFixed() ,从而导致render引发异常,并阻止解析器调用setSelectionRange

  2. Your logic that is swapping commas for decimals is not being used in your formatter. 格式化程序中未使用将逗号替换为小数的逻辑。 A value with a comma will come in, and the regex creating clean will remove it because it is expecting a decimal. 带有逗号的值将输入,而创建clean的正则表达式将删除它,因为它期望使用小数。 Once you fix that, you will have to also fix the comparison between val and clean at the end to swap decimals back to commas in clean . 解决此问题后,还必须最后修复valclean之间的比较,以将小数交换回clean逗号。

Overall, I would propose the following: 总体而言,我将提出以下建议:

  1. Swap if (typeof decimalCount === "number") to if (typeof ngModelCtrl.$modelValue === "number") if (typeof decimalCount === "number")交换为if (typeof ngModelCtrl.$modelValue === "number")
  2. Replace all commas with decimals before generating clean 在生成clean之前,用小数替换所有逗号
  3. Replace all decimals with commas in clean before comparing it back to the original val . 更换用逗号所有小数clean比较回原来的前val

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM