javascript - 如何使过滤后的输入能够在其中进行编辑,而不是在最后进行?

标签 javascript angularjs input-filter

在我正在从事的一个项目中,我的团队最近在 JavaScript/Angular 中开发了一种“屏蔽”输入,该输入作为依赖于过滤器的指令,以便向用户显示美国格式的电话号码电话号码。由于我们的应用程序仅在美国使用,因此我们不必担心使其能够灵活地适应其他国家/地区的电话格式。

对于那些不熟悉的人来说,这是美国电话号码的常用格式:

(AAA) EEE-TTTT xXXXXX

地点:

  • A:区号
  • E:交换代码
  • T:终端代码
  • X:扩展

我最初要解决的问题是,尝试编辑区号会导致光标跳到电话号码的末尾。更深层次的问题是,由于我们当前对该指令的实现,尝试在电话号码中间插入任何信息都会导致光标跳到末尾!

以下是它的实现和使用方式:

标记:

<input type="text"
       id="some-phone-number"
       name="somePhoneNumber"
       class="form-control"
       data-ng-model="vm.somePhoneNumber" 
       phone-input />

指令:

angular.module('app').directive('phoneInput', [
    '$filter', '$browser', phoneInputDir
]);

function phoneInputDir($filter, $browser) {
    return {
        require: 'ngModel',
        link: function($scope, $element, $attrs, ngModelCtrl) {
            var listener = function() {
                var value = $element.val().replace(/[^0-9]/g, '');
                $element.val($filter('tel')(value, false));
            };

            ngModelCtrl.$formatters.unshift(function (modelValue) {
                return $filter('tel')(modelValue, false);
            });

            // This runs when we update the text field
            ngModelCtrl.$parsers.push(function(viewValue) {
                return viewValue.replace(/[^0-9]/g, '').slice(0, 15);
            });

            // This runs when the model gets updated on the scope directly and keeps our view in sync
            ngModelCtrl.$render = function() {
                $element.val($filter('tel')(ngModelCtrl.$viewValue, false));
            };

            $element.bind('change', listener);
            $element.bind('keydown', function(event) {
                var key = event.keyCode;
                // If the keys include the CTRL, SHIFT, ALT, or META keys, or the arrow keys, do nothing.
                // This lets us support copy and paste too
                if (key == 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) {
                    return;
                }
                $browser.defer(listener); // Have to do this or changes don't get picked up properly
            });

            $element.bind('paste cut', function() {
                $browser.defer(listener);
            });
        }
    };
}    

过滤器:

angular.module('app').filter('tel', function() {
    return function(input) {
        console.log(input);
        if (!input) {
            return '';
        }

        var value = input.toString().trim().replace(/^\+/, '');

        if (value.match(/[^0-9]/)) {
            return input;
        }

        // Phone number format: 
        // (AAA) EEE-TTTT xXXXXX...
        var areaCode = value.slice(0, 3),
            exchangeCode = value.slice(3, 6),
            terminalCode = value.slice(6, 10),
            extension = value.slice(10);

        var result = '';
        if (areaCode)
            result += '(' + areaCode + ') ';
        if (exchangeCode)
            result += exchangeCode;
        if (terminalCode)
            result += '-' + terminalCode;
        if (extension)
            result += ' x' + extension;

        return result;
    };
});

问题:我可以通过什么方式更改此处的指令/过滤器以便能够进行内联编辑,而不是通过任何按键导致光标移动到输入的末尾?

最佳答案

由于您要动态更新输入中的文本,因此必须在更新之前存储光标位置,然后在更新后设置它。您还需要在光标位置添加 1 以考虑您要插入的字符。要实现此目的,您可以修改指令中的监听器函数,如下所示:

var listener = function() {
    var cursorPos = $element[0].selectionStart + 1;
    var value = $element.val().replace(/[^0-9]/g, '');
    $element.val($filter('tel')(value, false));
    $element[0].setSelectionRange(cursorPos, cursorPos);
};

由于 $element 是一个选择器,而不是实际的 HTML 元素本身,因此您需要引用第一个子元素( HTML 元素),这就是 $element[0] 的原因必须使用

关于javascript - 如何使过滤后的输入能够在其中进行编辑,而不是在最后进行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35989580/

相关文章:

javascript - 如何在 JavaScript 中重做 for...of 循环?

javascript - React 服务器端渲染还是静态index.html?

javascript - 将复选框更改为开关样式按钮

javascript - Angularjs - 选择下拉菜单的 Bootstrap 设置

java - 使用 Selenium 上传 APK 文件

javascript - 使用 angularjs Controller 作为样式的双重数据绑定(bind)

c++ - DirectShow 筛选器未显示为输入捕获设备

javascript - 如果 $.post() 在函数中,jQuery .show() 不会出现