代码之家  ›  专栏  ›  技术社区  ›  Happy Ahmad

角度指令:仅允许数字

  •  5
  • Happy Ahmad  · 技术社区  · 7 年前

    这里是 a sample angular directive to prevent typing non-numeric keys (StackOverflow answer) . 我想写点什么 this fiddle 在多个输入中使用is number指令。请考虑,由于我的输入中有各种不同的指令,我不能使用上述答案更新中建议的相同模板。

    var $scope;
    var app = angular.module('myapp', []);
    
    app.controller('Ctrl', function($scope) {
        $scope.myNnumber1 = 1;
        $scope.myNnumber2 = 1;
    });
    
    app.directive('isNumber', function () {
        return {
            require: 'ngModel',
            link: function (scope, element) {   
                scope.$watch(element.ngModel, function(newValue,oldValue) {
                    newValue = String(newValue);
                    newValue = newValue.replace('Û°', '0').replace('Û±', '1').replace('Û²', '2').replace('Û³', '3').replace('Û´', '4').replace('Ûµ', '5').replace('Û¶', '6').replace('Û·', '7').replace('Û¸', '8').replace('Û¹', '9');
                    var arr = String(newValue).split("");
                    if (arr.length === 0) return;
                    if (arr.length === 1 && (arr[0] == '-' || arr[0] === '.' )) return;
                    if (arr.length === 2 && newValue === '-.') return;
                    if (isNaN(newValue)) {
                        element.ngModel = oldValue;
                    }
                });
            }
       };
    

    更新: 请考虑我需要做一些处理来转换非英语数字等等。我创建了 a new fiddle here 基于Angular\u 10的答案。现在,除了键入波斯数字时光标的位置外,一切都很好。当我键入一个波斯语数字时,它被替换为英语的等效数字,但光标突然跳到了末尾。

    2 回复  |  直到 7 年前
        1
  •  6
  •   ngCoder    7 年前

    好啊考虑到您的要求,我自由地编写了更多定制指令。

    这是 fiddle 同样的

    问题

    您引用并更改给定指令的示例导致了此问题。

    1. HTML/JS中的$scope变量名错误($scope.myNnumber1=1; $范围。myNnumber2=1;在JS和HTML中,它是ng model=“myNumber1”)
    2. 您正在访问 element ng-model 并试图通过指令对其进行修改,这是不好的做法,也是指令不起作用的根本原因。因为您没有更改 ng-model 值,但反过来修改angular无法识别的HTML元素值。
    3. 更多过度使用 $watch 出于性能考虑,in指令并不总是可取的。

    解决方案

    app.directive('isNumber', function() {
        return {
            require: 'ngModel',
            restrict: 'A',
            link: function(scope, element, attr, ctrl) {
                function inputValue(val) {
                    if (val) {
                        var numeric = val.replace(/[^- 0-9]/g, '');
    
                        if (numeric !== val) {
                            ctrl.$setViewValue(numeric );
                            ctrl.$render();
                        }
                        return numeric;
                    }
                    return undefined;
                }
                ctrl.$parsers.push(inputValue);
            }
        };
    
    });
    

    当指令要求控制器通信时,我们可以在link函数中将控制器作为4个参数传递。通过该Ctrl参数,我们可以修改/查看控制器范围中的内容。

    使用一些基本regex表达式找出输入的内容,并在控制器范围对象视图值中进行设置。

    ctrl.$setViewValue(numeric); //to set the value in the respective ngModdel
    ctrl.$render(); //to display the changed value
    

    更多关于 $setViewValue

        2
  •  0
  •   Happy Ahmad    7 年前

    我最终使用了下面的指令。此指令转换波斯数字,并且不允许在文本框中键入任何数字。特别感谢Angular\u 10。我为他的帮助给了他50块赏金。

    app.directive('fixPersianAndNoNumberInput', function ($filter) {
        return {
            require: 'ngModel',
            restrict: 'EA',
            link: function (scope, element, attr, controller) {
                function inputValue(val) {
                    if (val) {
                        let numeric = parseInt(String(val).replace('Û°', '0').replace('Û±', '1').replace('Û²', '2').replace('Û³', '3').replace('Û´', '4').replace('Ûµ', '5').replace('Û¶', '6').replace('Û·', '7').replace('Û¸', '8').replace('Û¹', '9').replace(' ', '000').replace(/[^- 0-9]/g, ''));
                        if (numeric !== val) {
                            controller.$setViewValue(numeric);
                            controller.$render();
                            let value;
                            let updateOn, debounce;
                            if (controller.$options) {
                                if (controller.$options.getOption) {
                                    updateOn = controller.$options.getOption('updateOn');
                                    debounce = controller.$options.getOption('debounce');
                                } else {
                                    updateOn = controller.$options.updateOn;
                                    debounce = controller.$options.debounce;
                                }
                            }
                            if (updateOn === 'blur' || debounce) {
                                value = controller.$viewValue;
                                for (let i = controller.$parsers.length - 1; i >= 0; i--) {
                                    value = controller.$parsers[i](value);
                                }
                            } else {
                                value = controller.$$rawModelValue;
                            }
                            for (let j = controller.$formatters.length - 1; j >= 0; j--) {
                                value = controller.$formatters[j](value);
                            }
                            controller.$viewValue = value;
                            controller.$render();
                        }
                        return numeric;
                    }
                    return undefined;
                }
    
                controller.$parsers.push(inputValue);
                controller.$formatters.push((value) => {
                    if ([undefined, null, ''].indexOf(value) === -1) {
                       return $filter('currency')(value, '', 0);
                    }
                    return value;
                });
            }
        };
    });