2016-06-27 31 views
12

Ho bisogno di una direttiva per filtrare un campo per la valuta, quindi un utente deve solo digitare e il decimale è implicito.Direttiva di formattazione del denaro in Angular

Bisogni:

  1. Formato campo decimale come utente digita -

Inizia nel luogo centesimi mentre l'utente. Così avrebbero digitare "4" e vedere "0,04", tipo "42" e vedere "0.42", tipo 298023 e vedere "2.980,23"

  1. Il campo deve essere un numero
  2. deve consentire negativi -
  3. consentire 0.00 come ingresso numero
  4. Preferirei usare type = "numero", ma "type = text" va bene
  5. Si dovrebbe essere in grado di cancellare il campo per essere vuoto.

Il filtro di valuta ng non soddisfa questi requisiti così com'è. Si prega di vedere il comportamento in plunkers per vedere cosa intendo.

Il mio First Plunker ha `input = testo 'e consente numeri negativi. Un problema è che non è possibile digitare un negativo come il primo numero. Quando si cancella il campo, ritorna a "0.00" ma dovrebbe essere completamente cancellato.

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; 
       }); 
      } 
     }; 

}]); 

mio Second Plunker ha input = text e permette di ingresso negativo. Come il primo plunker, non consentirà un negativo come primo carattere, solo dopo aver digitato i numeri. Il secondo è che inizia al decimo posto anziché al centesimo. (Se si digita '3' si dovrebbe vedere '0.03' ma qui si vede '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); 
     } 
    }; 
}]); 

Come posso conciliare queste soluzioni o su misura uno per soddisfare i requisiti? Voglio evitare librerie o componenti aggiuntivi aggiuntivi. Mi è stato detto che l'approccio migliore sarebbe studiare la fonte del filtro di valuta e ricreare quel filtro con i requisiti aggiuntivi. Mi piacerebbe farlo, ma in questo momento non ne ho le capacità. Queste due direttive sono ciò che ho.

+3

angolare dispone di un filtro di valuta costruito in: https://docs.angularjs.org/api/ng/filter/currency –

+0

@ SSC-hrep3 che il filtro è bello, ma non soddisfa il requisiti per l'aggiunta di un punto decimale come tipi di utente. Questo è ciò che la direttiva è per. Per vedere cosa intendo, digita il campo plunker e guarda cosa succede. – jenryb

+1

Salve, [valuta-ng] (https://github.com/aguirrel/ng-currency) è utile. – Maher

risposta

7

. :: Risposta aggiornata - 14 luglio ::.


controllare questo semplice direttiva:

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); 
     } 
    }; 
}]); 

e usarlo in questo modo:

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

vederla dal vivo in questo PLUNKER (14 luglio)

+0

Chiudi, ma questo non aggiunge un decimale dopo due cifre, che dovrebbe riflettere sia nella vista che nel modello. – jenryb

+0

@jenryb Vuoi dire, vuoi forzare 2 cifre dopo il punto decimale? –

+0

Sì. Vedi il comportamento di uno dei plunkers per vedere cosa intendo – jenryb

3

Penso che questo possa pieno riempire il vostro requisito

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

è possibile limitare l'ingresso che consente solo numeri con decimali di predefinite validazioni di input angolari o utilizzando il codice char.

1

angolare Numerico

Angular Numeric è una direttiva sofisticata che implementa un campo di input numerico completo.

Molto semplice da usare, ma potente.

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

Non ci sono controlli sui valori minimi e massimi. Quando il valore scende al di sotto del valore minimo , il valore viene impostato sul valore minimo. Quando il valore supera il massimo, il valore viene impostato sul valore massimo.

La formattazione viene eseguita sull'evento sfocatura; migliaia separatore e decimale si basano sul locale Angular corrente.

È possibile impostare il numero di decimali.

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

+0

Non esattamente quello che sto cercando. Non voglio formattare su sfocatura, invece dovrebbe essere mentre l'utente digita. – jenryb

Problemi correlati