Подтвердить что ты не робот

Angular, поле ввода с директивой маски валюты для денег на лету

Я пытаюсь создать маску ввода для денежного поля ЕС, используя http://jquerypriceformat.com/

До сих пор в моей директиве вход правильно показывал пользователю с применением маски, но я считаю, что там что-то не так, потому что значения POST отправляются со странным форматированием, совершенно отличным от того, что мы видим в поле ввода.

Я включаю priceformat.js

<script src="js/jquery.price_format.1.8.min.js"></script>

<input type="text" currency-input ng-model...>

И на angular:

app.directive('currencyInput', function() {
    return {
      require: '?ngModel',
      link: function($scope, element, attrs, controller) {
        element.priceFormat({
            prefix: '',
            centsSeparator: ',',
            thousandsSeparator: '.'
        });
      }
    };
});

Мой ввод показывает значение с помощью маски правильно, но по данным POST (называемой angular) это другое значение, что мне не хватает?

input > 2.200,80 | пост > 22 0080

Спасибо

4b9b3361

Ответ 1

В вашем примере я не вижу, что ссылка возвращает что-то.

Я бы написал директиву что-то вроде:

.directive('format', ['$filter', function ($filter) {
    return {
        require: '?ngModel',
        link: function (scope, elem, attrs, ctrl) {
            if (!ctrl) return;


            ctrl.$formatters.unshift(function (a) {
                return $filter(attrs.format)(ctrl.$modelValue)
            });


            ctrl.$parsers.unshift(function (viewValue) {

          elem.priceFormat({
            prefix: '',
            centsSeparator: ',',
            thousandsSeparator: '.'
        });                

                return elem[0].value;
            });
        }
    };
}]);

Демо 1 Fiddle

enter image description here

Если вы хотите запустить огонь фильтра, используйте $formatters:

Теперь link:

link: function (scope, elem, attrs, ctrl) {
            if (!ctrl) return;

            var format = {
                    prefix: '',
                    centsSeparator: ',',
                    thousandsSeparator: ''
                };

            ctrl.$parsers.unshift(function (value) {
                elem.priceFormat(format);

                return elem[0].value;
            });

            ctrl.$formatters.unshift(function (value) {
                elem[0].value = ctrl.$modelValue * 100 ;
                elem.priceFormat(format);
                return elem[0].value;
            })
        }

Демо 2 Fiddle

Ответ 2

Нажмите a $parser на контроллер и обновите значение только в том случае, если оно не соответствует входу с помощью $setViewValue() и $render().

app.directive('currencyInput', function() {
    return {
      require: '?ngModel',
      link: function($scope, element, attrs, controller) {
        return ctrl.$parsers.push(function(inputValue) {

            ...

            if (result != inputValue) {
                controller.$setViewValue(res);
                controller.$render();
            }
        });
      }
    };
});

Здесь сценарий с логикой, которую я использовал для моей директивы ввода валюты: Fiddle

Ответ 3

Поздно к партии, но я считаю, что это заслуживает другого ответа! Я использовал модуль ng-currency. Это абсолютно фантастический.

Ответ 4

Мне нравится дублинский подход, вызывающий его простоту и элегантность. Я решил добавить (с соответствующими кредитами) некоторые функции поверх него, чтобы сделать его очень близким к реальному использованию.

Я использую его в проекте github для создания полезных директив финансирования github.

Известные дополнительные функции:

  • Он выполняет некоторую строгую проверку входов, чтобы дать правильный ответ.
  • У него есть несколько сочетаний клавиш, чтобы быстрее вводить большие числа.
  • Я покажу, как интегрировать его с обновлениями bootstrap и ngmodel css.
  • В качестве бонуса я вывел форму ngmonel как JSON, чтобы помочь людям увидеть, как валидация формы работает в режиме реального времени.

Он также использует POJO в качестве ngmodel:

function Money() {
    this.notional = 0;
    this.maxValue = 99999999999.9;
    this.maxValueString = "99,999,999,999.9";
    this.maxPrecision = 10;
}

вы можете использовать его с Bootstrap 3 следующим образом:

<h1>Currency Formatting directive</h1>

<div class="row">

    <div class="col-md-6">
        <form name="myForm">

            <div class="form-group" ng-class="{'has-error': myForm.notional.$invalid && myForm.notional.$touched}">
                <input type="text" ng-model="myForm.money.notional  " money="money" money-input size="30" required
                       name="notional"
                       class="form-control"
                       placeholder="Enter notional amount"/>

                      <p class="help-block error" ng-show="myForm.notional.$error.required && myForm.notional.$touched">Required</p>



            </div>

            <button ng-disabled="myForm.$invalid" type="submit">SAVE</button>
        </form>
        <h2>Tips</h2>
        <ol>

            <li> Entering 'k' will multiply the amount by one thousand</li>
            <li> Entering 'm' will multiply the amount by one million</li>
            <li> Entering 'b' will multiply the amount by one billion</li>
        </ol>
    </div>
</div>
<p>Form debugger</p>
<pre>
               form = {{ myForm | json }}
    </pre>

Ответ 5

Здесь можно обработать это без jQuery, используя только директиву Angular. Этот пример не поддерживает десятичные знаки. Легко изменить его, чтобы поддержать это, но просто измените $filter в функции toView().

По-моему, это лучший подход для решения одной и той же проблемы, так как вы можете избежать загрузки в jQuery и плагин валюты, упомянутый автором. Поддержка локалей для евро должна поддерживаться с помощью свойств $locale, но я тестировал это только для использования в долларах США.

(function() {
  var app = angular.module('currencyMask', []);

  // Controller
  app.controller('ctrl', ['$scope', function($scope) {
    $scope.amount = 100000;
  }]);

  // Directive
  app.directive('inputCurrency', ['$locale', '$filter', function($locale, $filter) {

    // For input validation
    var isValid = function(val) {
      return angular.isNumber(val) && !isNaN(val);
    };

    // Helper for creating RegExp's
    var toRegExp = function(val) {
      var escaped = val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
      return new RegExp(escaped, 'g');
    };

    // Saved to your $scope/model
    var toModel = function(val) {

      // Locale currency support
      var decimal = toRegExp($locale.NUMBER_FORMATS.DECIMAL_SEP);
      var group = toRegExp($locale.NUMBER_FORMATS.GROUP_SEP);
      var currency = toRegExp($locale.NUMBER_FORMATS.CURRENCY_SYM);

      // Strip currency related characters from string
      val = val.replace(decimal, '').replace(group, '').replace(currency, '').trim();

      return parseInt(val, 10);
    };

    // Displayed in the input to users
    var toView = function(val) {
      return $filter('currency')(val, '$', 0);
    };

    // Link to DOM
    var link = function($scope, $element, $attrs, $ngModel) {
      $ngModel.$formatters.push(toView);
      $ngModel.$parsers.push(toModel);
      $ngModel.$validators.currency = isValid;

      $element.on('keyup', function() {
        $ngModel.$viewValue = toView($ngModel.$modelValue);
        $ngModel.$render();
      });
    };

    return {
      restrict: 'A',
      require: 'ngModel',
      link: link
    };
  }]);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>

<div ng-app="currencyMask" ng-controller="ctrl">
	<input input-currency ng-model="amount">
	<p><strong>Amount:</strong> {{ amount }}</p>
</div>