Директива о форматировании денег в Angular

Мне нужна директива для фильтрации поля для валюты, поэтому пользователю просто нужно ввести тип и указать десятичное значение.

Потребности:

  • Форматировать десятичное поле как пользовательские типы -

Начните с сотых по количеству пользователей. Поэтому они набирают "4" и видят "0.04", типа "42" и см. "0,42", тип 298023 и см. "2980.23"

  1. Поле должно быть числом
  2. Должен разрешить негативы -
  3. Разрешить 0.00 как числовой ввод
  4. Идеально использовать type = "number", но "type = text" в порядке
  5. Вы должны очистить поле пустым.

Фильтр ng-валюты не выполняет эти требования как есть. Пожалуйста, см. Поведение в plunkers, чтобы понять, что я имею в виду.

My Первый Plunker имеет` input = text 'и позволяет отрицательные числа. Одна из проблем заключается в том, что вы не можете набрать отрицательный номер как самый первый номер. Когда вы очищаете поле, оно возвращается к "0.00", но оно должно полностью очищаться.

   app.directive('format', ['$filter', function ($filter) {
 return {
            require: 'ngModel', //there must be ng-model in the html
            link: function (scope, elem, attr, ctrl) {
                if (!ctrl) return;

                ctrl.$parsers.unshift(function (viewValue, modelValue) {
                    var plainNumber = viewValue.replace(/[^-+0-9]/g,'');
                    var newVal = plainNumber.charAt(plainNumber.length-1);
                    var positive = plainNumber.charAt(0) != '-';
                    if(isNaN(plainNumber.charAt(plainNumber.length-1))){
                      plainNumber = plainNumber.substr(0,plainNumber.length-1)
                    }
                    //use angular internal 'number' filter
                    plainNumber = $filter('number')(plainNumber / 100, 2).replace(/,/g, '');
                    if(positive && newVal == '-'){
                      plainNumber = '-' + plainNumber;
                    }
                    else if(!positive && newVal == '+'){
                      plainNumber = plainNumber.substr(1);
                    }
                    plainNumber.replace('.', ',');

                    //update the $viewValue
                    ctrl.$setViewValue(plainNumber);
                    //reflect on the DOM element
                    ctrl.$render();
                    //return the modified value to next parser
                    return plainNumber;
                });
            }
        };

}]);

Мой Второй плункер имеет input = text и допускает отрицательный ввод. Подобно первому плункеру, он не позволит отрицать как первый символ, только после ввода цифр. Во-вторых, он начинается в десятом месте вместо сотых. (если вы наберете "3", вы должны увидеть "0.03", но здесь он показывает "0,3" )

app.directive('inputRestrictor', [function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModelCtrl) {
            var pattern = /[^.0-9+-]/g;

            function fromUser(text) {
                if (!text)
                return text;

                var rep = /[+]/g;
                var rem = /[-]/g;
                rep.exec(text);
                rem.exec(text);

                var indexp = rep.lastIndex;
                var indexm = rem.lastIndex;
                text = text.replace(/[+.-]/g, '');
                if (indexp > 0 || indexm > 0) {
                    if (indexp > indexm) text = "+" + text; // plus sign?
                    else text = "-" + text;
                }

                var transformedInput = text.replace(pattern, '');
                transformedInput = transformedInput.replace(/([0-9]{1,2}$)/, ".$1")
                ngModelCtrl.$setViewValue(transformedInput);
                ngModelCtrl.$render();
                return transformedInput;
            }

            ngModelCtrl.$parsers.push(fromUser);
        }
    };
}]);

Как я могу примирить эти решения или адаптировать их для удовлетворения требований? Я хочу избежать дополнительных библиотек или надстроек. Мне сказали, что наилучшим подходом будет изучение источника для фильтра валюты и воссоздание этого фильтра с дополнительными требованиями. Я бы с удовольствием это сделал, но у меня действительно нет навыков для этого прямо сейчас. Эти две директивы - это то, что у меня есть.

Ответ 1

.:: Обновленный ответ - 14 июля::.


Проверьте эту простую директиву:

app.directive('price', [function () {
    return {
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {
            attrs.$set('ngTrim', "false");

            var formatter = function(str, isNum) {
                str = String( Number(str || 0) / (isNum?1:100) );
                str = (str=='0'?'0.0':str).split('.');
                str[1] = str[1] || '0';
                return str[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') + '.' + (str[1].length==1?str[1]+'0':str[1]);
            }
            var updateView = function(val) {
                scope.$applyAsync(function () {
                    ngModel.$setViewValue(val || '');
                    ngModel.$render();
                });
            }
            var parseNumber = function(val) {
                var modelString = formatter(ngModel.$modelValue, true);
                var sign = {
                    pos: /[+]/.test(val),
                    neg: /[-]/.test(val)
                }
                sign.has = sign.pos || sign.neg;
                sign.both = sign.pos && sign.neg;

                if (!val || sign.has && val.length==1 || ngModel.$modelValue && Number(val)===0) {
                    var newVal = (!val || ngModel.$modelValue && Number()===0?'':val);
                    if (ngModel.$modelValue !== newVal)
                        updateView(newVal);

                    return '';
                }
                else {
                    var valString = String(val || '');
                    var newSign = (sign.both && ngModel.$modelValue>=0 || !sign.both && sign.neg?'-':'');
                    var newVal = valString.replace(/[^0-9]/g,'');
                    var viewVal = newSign + formatter(angular.copy(newVal));

                    if (modelString !== valString)
                        updateView(viewVal);

                    return (Number(newSign + newVal) / 100) || 0;
                }
            }
            var formatNumber = function(val) {
                if (val) {
                    var str = String(val).split('.');
                    str[1] = str[1] || '0';
                    val = str[0] + '.' + (str[1].length==1?str[1]+'0':str[1]);
                }
                return parseNumber(val);
            }

            ngModel.$parsers.push(parseNumber);
            ngModel.$formatters.push(formatNumber);
        }
    };
}]);

И используйте его следующим образом:

<input type="text" ng-model="number" price >

Посмотрите это в прямом эфире PLUNKER (14 июля)

Ответ 2

Я думаю, что это может заполнить ваше требование

https://github.com/FCSAmerica/angular-fcsa-number

вы можете ограничить ввод, который позволяет использовать только числа с десятичными знаками по умолчанию angular входные проверки или с помощью кода char.

Ответ 3

Angular Числовое

Angular Numeric - это сложная директива, которая реализует полное числовое поле ввода.

Очень простой в использовании - но мощный.

<input numeric min="-20" max="100" decimals="3" />

Проверяются значения min и max. Когда значение падает ниже minumum значение установлено на значение minumum. Когда значение превышает maxiumum, значение устанавливается на максимум.

Форматирование выполняется при событии размытия; тысяч разделителей и десятичных основаны на текущей локали Angular.

Можно задать число десятичных знаков.

https://www.npmjs.com/package/angular-numeric-directive