Vue formatée d'entrée du numéro AngularJS
-
20-12-2019 - |
Question
Je souhaite utiliser une entrée numérique formatée pour afficher des milliers de points séparateurs à l'utilisateur lorsqu'il tape de gros nombres.Voici le code de la directive que j'ai utilisé : http://jsfiddle.net/LCZfd/3/
Quand j'utilise input type="text"
ça marche, mais quand je veux utiliser input type="number"
c'est étrangement un nettoyage par quelque chose lorsque l'utilisateur tape de gros nombres.
Quel est le problème input[number]
?
La solution
Comme écrit dans les commentaires, input type="number"
ne prend en charge que les chiffres, un séparateur décimal (généralement ,
ou .
selon les paramètres régionaux) et -
ou e
.Vous pouvez toujours entrer ce que vous voulez, mais le navigateur supprimera tout caractère inconnu/incorrect.
Cela vous laisse 2 options :
- Utiliser
type="text"
et validation de modèle commepattern="[0-9]+([\.,][0-9]+)*"
pour limiter ce que l'utilisateur peut saisir tout en formatant automatiquement la valeur comme vous le faites dans ton exemple. - Placez une superposition au-dessus du champ de saisie qui restitue les nombres comme vous le souhaitez tout en permettant à l'utilisateur d'utiliser la personnalisation.
type="number"
contrôles d'entrée, comme démontré ici.
Cette dernière solution utilise un supplément <label>
balise qui contient la valeur actuelle et est masquée via CSS lorsque vous concentrez le champ de saisie.
Autres conseils
Vous devez ajouter le step
attribuer à votre number
saisir.
<input type="number" step="0.01" />
Cela autorisera les points flottants.
De plus, je vous recommande de consulter le fil de discussion sur les bugs sur number
entrées dans Firefox.Vous voudrez peut-être envisager pas en utilisant ce type d'entrée, car il vient tout juste d'être pris en charge dans ce sortie de FF.
Toutes ces années plus tard, il n’existe toujours pas de solution HTML5 prête à l’emploi pour cela.
j'utilise <input type="tel">
ou <input type="text">
("tel" fait apparaître un clavier numérique sous Android et iOS, ce qui dans certains cas est un bonus.)
Ensuite, j'avais besoin d'une directive pour :
- filtrer les caractères non numériques
- ajouter des virgules de séparateur de milliers au fur et à mesure que l'utilisateur tape
- utiliser
$parsers
etkeyup
mettre en placeelem.val()
et$formatters
pour régler l'affichage... - ...dans les coulisses, attribuez
ng-model
un nombre à virgule flottante
L'exemple de directive ci-dessous fait cela et accepte les nombres négatifs et à virgule flottante, sauf si vous spécifiez que vous ne souhaitez que des nombres positifs ou entiers.
Ce n'est pas la solution complète que j'aimerais, mais je pense qu'elle comble le fossé.
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;
}
}
};
});
Vous ne pouvez pas utiliser de valeurs avec ,
parce que type=number
ne prend que des nombres, l'ajout d'une virgule en fait une chaîne.
Voir http://jsfiddle.net/LCZfd/5
Il vaut mieux créer vos propres contrôles si vous voulez des virgules.Un avec une vraie valeur (le nombre) et une valeur d'affichage (la chaîne).
vous pouvez essayer ceci, j'ai modifié la directive que j'ai vue ici...Comment puis-je restreindre une saisie pour n’accepter que des chiffres ? ...
voici la directive modifiée que j'ai faite...Cette directive utilise l'événement keyup pour modifier l'entrée à la volée...
.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();
}
}
});
}
};
tu l'utilises comme ça...
<input type="text" ng-model="amountallocated" id="amountallocated" numeric-only />