Vista formattata in ingresso Numero AngularJS
-
20-12-2019 - |
Domanda
Voglio utilizzare un input number formattato per mostrare mille punti separatorie all'utente quando tipi numeri grandi.Ecco il codice direttivo che ho usato: http://jsfiddle.net/lczfd/3/ .
Quando utilizzo input type="text"
funziona, ma quando voglio usare input type="number"
è una pulizia stranamente con qualcosa quando l'utente digita numeri grandi.
Qual è il problema su input[number]
?
Soluzione
Come scritto nei commenti, input type="number"
non supporta nulla ma cifre, un separatore decimale (di solito ,
o .
a seconda delle impostazioni locali) e -
o e
. Puoi ancora Inserisci Qualunque cosa tu voglia, ma il browser scarterà qualsiasi carattere sconosciuto / errato.
Questo ti lascia con 2 opzioni:
- .
- Utilizzare
type="text"
e convalida del modello comepattern="[0-9]+([\.,][0-9]+)*"
per limitare ciò che l'utente può inserire durante la formattazione del valore come si esegue automaticamente il valore come si esegue in Il tuo esempio . - Metti una sovrapposizione sulla parte superiore del campo di input che rende i numeri come si desidera e consente comunque all'utente di utilizzare i controlli di ingresso personalizzati
type="number"
, come dimostrato qui .
Quest'ultima soluzione utilizza un tag <label>
aggiuntivo che contiene il valore corrente ed è nascosto tramite CSS quando si focalizza il campo di input.
Altri suggerimenti
È necessario aggiungere l'attributo step
all'ingresso number
.
<input type="number" step="0.01" />
.
Ciò consentirà i punti flottanti.
Inoltre, consiglierei di rivedere il filo del bug su ingressi number
in Firefox.Si consiglia di considerare non usando questo tipo di ingresso, poiché è stato appena supportato in rilascio di ff.
Tutti questi anni dopo, non c'è ancora una soluzione HTML5 fuori dalla scatola per questo.
Sto usando <input type="tel">
o <input type="text">
("Tel" offre una tastiera numerica in Android e IOS, che in alcuni casi è un bonus.)
Allora avevo bisogno di una direttiva su:
- .
- Filtrare i caratteri non numerici
- Aggiungere mille virgolette come tipo utente
- Utilizzare
$parsers
ekeyup
per impostareelem.val()
e$formatters
per impostare il display ... - ... Mentre dietro le quinte, assegna
ng-model
un numero punto di galleggiamento
L'esempio della direttiva seguente è questo, e accetta negativi e numeri del punto flottante a meno che non si specifichi di volere solo positivi o numeri interi.
Non è la soluzione completa che vorrei, ma penso che colpisca il divario.
HTML
<input type="text" ng-model="someNumber" number-input />
.
JavaScript
myApp.directive('numberInput', function($filter) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(modelValue) {
return setDisplayNumber(modelValue, true);
});
// it's best to change the displayed text using elem.val() rather than
// ngModelCtrl.$setViewValue because the latter will re-trigger the parser
// and not necessarily in the correct order with the changed value last.
// see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
// for an explanation of how ngModelCtrl works.
ngModelCtrl.$parsers.push(function(viewValue) {
setDisplayNumber(viewValue);
return setModelNumber(viewValue);
});
// occasionally the parser chain doesn't run (when the user repeatedly
// types the same non-numeric character)
// for these cases, clean up again half a second later using "keyup"
// (the parser runs much sooner than keyup, so it's better UX to also do it within parser
// to give the feeling that the comma is added as they type)
elem.bind('keyup focus', function() {
setDisplayNumber(elem.val());
});
.
function setDisplayNumber(val, formatter) {
var valStr, displayValue;
if (typeof val === 'undefined') {
return 0;
}
valStr = val.toString();
displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
displayValue = parseFloat(displayValue);
displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';
// handle leading character -/0
if (valStr.length === 1 && valStr[0] === '-') {
displayValue = valStr[0];
} else if (valStr.length === 1 && valStr[0] === '0') {
displayValue = '';
} else {
displayValue = $filter('number')(displayValue);
}
.
// handle decimal
if (!attrs.integer) {
if (displayValue.indexOf('.') === -1) {
if (valStr.slice(-1) === '.') {
displayValue += '.';
} else if (valStr.slice(-2) === '.0') {
displayValue += '.0';
} else if (valStr.slice(-3) === '.00') {
displayValue += '.00';
}
} // handle last character 0 after decimal and another number
else {
if (valStr.slice(-1) === '0') {
displayValue += '0';
}
}
}
if (attrs.positive && displayValue[0] === '-') {
displayValue = displayValue.substring(1);
}
if (typeof formatter !== 'undefined') {
return (displayValue === '') ? 0 : displayValue;
} else {
elem.val((displayValue === '0') ? '' : displayValue);
}
}
.
function setModelNumber(val) {
var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
modelNum = parseFloat(modelNum);
modelNum = (!isNaN(modelNum)) ? modelNum : 0;
if (modelNum.toString().indexOf('.') !== -1) {
modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
}
if (attrs.positive) {
modelNum = Math.abs(modelNum);
}
return modelNum;
}
}
};
});
.
Non è possibile utilizzare i valori con ,
perché type=number
prende solo numeri, aggiungendo una virgola lo rende una stringa.
Vedi http://jsfiddle.net/lczfd/5
Stai meglio a creare i tuoi controlli se vuoi virgole.Uno con un valore reale (il numero) e un valore di visualizzazione (la stringa).
Puoi provare questo, ho modificato la direttiva che ho visto qui ... Come posso limitare un input soloAccetta numeri? ...
Ecco la Direttiva modificata che ho fatto ... Questa direttiva utilizza l'evento Keyup per modificare l'ingresso sul volo ...
.directive('numericOnly', function($filter) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
element.bind('keyup', function (inputValue, e) {
var strinput = modelCtrl.$$rawModelValue;
//filter user input
var transformedInput = strinput ? strinput.replace(/[^,\d.-]/g,'') : null;
//remove trailing 0
if(transformedInput.charAt(0) <= '0'){
transformedInput = null;
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}else{
var decimalSplit = transformedInput.split(".")
var intPart = decimalSplit[0];
var decPart = decimalSplit[1];
//remove previously formated number
intPart = intPart.replace(/,/g, "");
//split whole number into array of 3 digits
if(intPart.length > 3){
var intDiv = Math.floor(intPart.length / 3);
var strfraction = [];
var i = intDiv,
j = 3;
while(intDiv > 0){
strfraction[intDiv] = intPart.slice(intPart.length-j,intPart.length - (j - 3));
j=j+3;
intDiv--;
}
var k = j-3;
if((intPart.length-k) > 0){
strfraction[0] = intPart.slice(0,intPart.length-k);
}
}
//join arrays
if(strfraction == undefined){ return;}
var currencyformat = strfraction.join(',');
//check for leading comma
if(currencyformat.charAt(0)==','){
currencyformat = currencyformat.slice(1);
}
if(decPart == undefined){
modelCtrl.$setViewValue(currencyformat);
modelCtrl.$render();
return;
}else{
currencyformat = currencyformat + "." + decPart.slice(0,2);
modelCtrl.$setViewValue(currencyformat);
modelCtrl.$render();
}
}
});
}
.
};
Lo usi come questo ...
<input type="text" ng-model="amountallocated" id="amountallocated" numeric-only />
.