web-dev-qa-db-fra.com

Champ de saisie angulaire avec directive de masque monétaire pour le format monétaire à la volée

J'essaie de créer un masque de saisie pour un champ monétaire européen à l'aide de http://jquerypriceformat.com/

Jusqu'ici dans ma directive, l'entrée montre correctement à l'utilisateur avec le masque appliqué, mais je pense qu'il y a un problème, car les valeurs POST sont envoyées avec un formatage étrange, totalement différent de ce que nous voyons dans le champ d'entrée .

J'inclus le priceformat.js

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

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

Et sur angulaire:

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

Mon entrée montre correctement la valeur avec le masque, mais sur les données POST (appelées par angulaire), c'est une valeur différente, que me manque-t-il?

entrée> 2.200,80 | poste> 22 0080

Merci

24
Antonio Max

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

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

.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

31
Maxim Shoustin

Poussez un $parser sur le contrôleur et mettez à jour la valeur uniquement si elle ne correspond pas à l'entrée à l'aide de $setViewValue() et $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();
            }
        });
      }
    };
});

Voici un tour de passe-passe avec la logique que j'ai utilisée pour ma directive de saisie monétaire: Fiddle

17
dubilla

En retard pour la fête, mais je crois que cela mérite une autre réponse! J'utilise le module ng-currency . C'est absolument fantastique.

3
David Posey

J'aime l'approche de Dubilla pour sa simplicité et son élégance. J'ai décidé d'ajouter (avec les crédits dus) quelques fonctionnalités en plus pour le rendre assez proche du cas d'utilisation réel. 

Je l’utilise sur un projet github pour créer des directives financières utiles github .

Caractéristiques supplémentaires notables:

  1. Il effectue un contrôle rigoureux des entrées pour donner une réponse valide.
  2. Il comporte des raccourcis clavier pour faciliter la saisie de grands nombres.
  3. Je montre comment l’intégrer avec les mises à jour css bootstrap et ngmodel.
  4. En prime, j'ai sorti le formulaire ngmonel en tant que JSON pour aider les gens à voir comment fonctionne la validation du formulaire en temps réel.

Il utilise également un POJO comme ngmodel:

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

vous pouvez l'utiliser avec Bootstrap 3 comme ceci:

<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>
1
Nikos

Voici un moyen de gérer cela sans jQuery en utilisant uniquement une directive angulaire. Cet exemple ne supporte pas les décimales. Il est facile de le modifier pour supporter cela, il suffit de changer le $filter dans la fonction toView().

À mon avis, il s'agit d'une meilleure approche pour résoudre le même problème, car vous pouvez éviter le chargement dans jQuery et dans le plug-in de devises mentionné par l'auteur. La prise en charge des paramètres régionaux pour Euro devrait être prise en charge par l’utilisation des propriétés $locale, mais je l’ai seulement testée pour une utilisation en USD.

(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>

0
Kevin Leary