AngularJS数字输入格式化视图

33
我想使用格式化数字输入,以便在用户输入大数字时向其显示千位分隔符。以下是我使用的指令代码:http://jsfiddle.net/LCZfd/3/ 当我使用时,它可以正常工作,但是当我想要使用时,当用户输入大数字时,它会被奇怪地清除。 input[number]有什么问题?

抱歉,我分享了错误的jsfiddle网址。我现在已经更新了它。 - Murat Çorlu
1
类似于这样的内容:http://jsfiddle.net/LCZfd/6/ - S.B.
input type="number" 仅支持实际数字,即数值为[0-9]、小数点(.)、可选负号(-)和指数符号"e"的数字。不允许在数字中使用逗号!只需使用 input type="text" 并具有帮助函数以将逗号分隔的文本解析为实际数字即可。 - basilikum
有趣的是,我可以通过键入在type=number中写入“1,000,000”,但如果我通过ng-model设置它,它会将所有内容都删除。这似乎有些错误。对你来说是正常的吗? - Murat Çorlu
请使用以下模块,它可能会对您有所帮助:http://ngmodules.org/modules/angular-input-decimal-separator - Jeeva J
显示剩余9条评论
5个回答

43

如评论中所述,input type="number" 只支持数字、小数点(通常是,.,取决于区域设置)以及-e。您仍然可以输入任何内容,但浏览器会丢弃任何未知/不正确的字符。

这使您有两个选择:

  • 使用type =“text”和模式验证,例如pattern="[0-9]+([\.,][0-9]+)*",限制用户输入,同时自动格式化值,就像在示例中所做的那样。
  • 在输入字段上叠加覆盖层,以您想要的方式呈现数字,并仍允许用户使用自定义type="number" 输入控件,就像此处演示的那样。

后一种解决方案使用附加的<label>标签,其中包含当前值,并通过CSS隐藏,当您聚焦输入字段时。


不错的解决方案!但是似乎小数没有被输入。有什么提示可以帮助我们实现吗?谢谢。 - Anoop Thiruonam
目标是将千位分隔符放入数字中,而不是小数点。支持两者变得更加棘手,因为当您不知道用户的语言环境时,您不知道他们输入的是小数还是千位分隔符。我的答案示例2应该适用于两种情况。 - S.B.
很棒的解决方案!对于$parsers和$formatters的解决方案,使用$setViewValue和$render来防止元素与视图不同步。(如果您尝试在jsfiddle中重复添加双逗号,您会看到这一点)。更多信息请参见https://github.com/angular/angular.js/issues/12544。 - Chris Chudzicki

8
所有这些年过去了,仍然没有一个HTML5的开箱即用解决方案。
我正在使用(在Android和iOS中,“tel”会弹出数字键盘,在某些情况下是一个奖励)。
然后我需要一个指令来:
- 过滤掉非数字字符 - 添加千位分隔符逗号,使用户输入时更加方便 - 使用$parsers和$keyup设置elem.val()和$formatters设置显示... - ...在幕后,将ng-model分配为浮点数
下面的指令示例可以实现此功能,并且除非您指定要求仅为正数或整数,否则它接受负数和浮点数。
这不是我想要的完整解决方案,但我认为它填补了空白。
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;
      }
    }
  };
});

https://jsfiddle.net/benlk/4dto9738/


6

抱歉我分享了错误的jsfiddle网址。我已经更新了正确的问题。所以我的问题不是关于浮点数。我想使用像“1,000,000”这样的千位分隔符。 - Murat Çorlu

2

你可以尝试这个,我修改了我在这里看到的指令... 如何限制输入只接受数字? ...

这是我修改的指令... 这个指令使用keyup事件实时修改输入...

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

};

你可以像这样使用它...

<input type="text" ng-model="amountallocated" id="amountallocated" numeric-only />

2

由于type=number只接受数字,因此您不能使用带有,的值,添加逗号会使其变成字符串。

请参见http://jsfiddle.net/LCZfd/5

如果您需要逗号,最好自己制作控件。一个控件包含真实值(数字)和显示值(字符串)。


有趣的是,我可以通过输入将“1,000,000”写入“type=number”,但如果我通过ng-model设置它,它就会删除所有内容。这似乎对我来说有点错误。你觉得这正常吗? - Murat Çorlu
1
是的,这很奇怪。手动输入“50,000”可以正常工作。内部它将value和valueAsNumber设置为50000,但它会显示50,000,并且按上/下箭头会删除逗号。 - Jahed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接